*{margin:0;padding:0;box-sizing:border-box}

/* html получает тот же фон, что и body — на iOS Safari эффект "резинки" при овер-скролле
   в начале/конце страницы на долю секунды показывает то, что находится ЗА body (обычно
   белую или чёрную дефолтную заливку браузера), а не сам фон сайта. Одинаковый фон на
   обоих уровнях убирает этот визуальный провал независимо от текущей темы. */
html{background-color:var(--bg-page, #0F1115)}

/* ===== Система тем и акцентных цветов =====
   Два независимых переключателя, оба через атрибуты на <html>:
   - data-theme: "dark" (по умолчанию) | "light" | "oled" — определяет фон/текст/границы.
   - data-accent: "purple" (по умолчанию) | "orange" | "red" | "green" | "blue" — определяет
     единственный акцентный цвет, который раньше был захардкожен как #8B5CF6 по всему файлу.
   Все компоненты ниже используют var(--accent) и var(--bg-*)/var(--text-*)/var(--border-*)
   вместо конкретных hex-значений, поэтому переключение — это просто смена атрибута в JS
   (см. APP.THEME в core.js), без пересчёта DOM. --accent-rgb хранится отдельным триплетом
   "R,G,B" (не hex) специально для использования внутри rgba(var(--accent-rgb),.2) — так
   прозрачные варианты акцента (свечения, полупрозрачные фоны) тоже следуют за темой. */
:root{
  --accent:#8B5CF6;
  --accent-rgb:139,92,246;
  --accent-light:#a78bfa;
  /* --holo-1..--holo-5 — пять цветов-остановок для linear-gradient() голо-акцентов,
     переопределяются в html[data-accent="holo-*"] ниже. У обычных (не-holo) акцентов
     все 5 равны var(--accent) — если override-блок ниже случайно попытается собрать
     градиент для обычной темы, получится просто сплошная заливка тем же цветом, что
     и раньше, без визуальной разницы. Анимация — плавный линейный перелив слева направо
     через background-position (см. @keyframes holoSweep ниже), а не вращение угла через
     @property/conic-gradient: тот подход давал эффект вращающегося CD-диска, что было
     решено сменить на более сдержанный и премиальный "бегущий свет", как у перламутра
     или карбона на солнце. */
  --holo-1:var(--accent);--holo-2:var(--accent);--holo-3:var(--accent);--holo-4:var(--accent);--holo-5:var(--accent);
  --holo-anim-duration:6s;

  --bg-page:#0F1115;
  --bg-card:#1A1D24;
  --bg-card-alt:#171b22;
  --bg-sidebar:#16191f;
  --bg-input:#171b22;
  --bg-row-border:#22262f;

  --border:#525C70;
  --border-soft:#68738A;

  --text-primary:#fff;
  --text-secondary:#9CA3AF;
  --text-muted:#6B7280;
  --text-footer:#777;

  --danger:#EF4444;
  --success:#22C55E;
}

html[data-accent="orange"]{--accent:#F97316;--accent-rgb:249,115,22;--accent-light:#fb923c;}
html[data-accent="red"]{--accent:#EF4444;--accent-rgb:239,68,68;--accent-light:#f87171;}
html[data-accent="green"]{--accent:#22C55E;--accent-rgb:34,197,94;--accent-light:#4ade80;}
html[data-accent="blue"]{--accent:#3B82F6;--accent-rgb:59,130,246;--accent-light:#60a5fa;}

/* ===== Голографические акценты =====
   Второй ряд тех же 5 цветов, но с переливающимся градиентом вместо плоской заливки —
   --accent/--accent-rgb/--accent-light остаются одним цветом (тем же базовым тоном)
   для мест, где градиент физически не работает (border-color, обычный text color,
   rgba() для теней/свечений); --holo-1..--holo-5 хранят отдельные цвета-остановки
   градиента для мест, которые физически МОГУТ быть градиентом.
   Анимация — background-position плавно едет от 0% к -200% (см. @keyframes holoSweep
   ниже), что даёт эффект бегущей слева направо волны света поверх background-size:300%
   растянутого linear-gradient — как перелив на карбоне/перламутре под углом, а не
   вращение (более ранняя версия через conic-gradient + @property давала эффект
   вращающегося CD-диска, который выглядел дёшево, а не премиально).
   Голограмма — это ОДИН цвет, который переливается по яркости/насыщенности при смене
   угла обзора, не радуга из разных цветов. Поэтому каждая палитра ниже — это один и
   тот же hue (тот же тон, что у обычного акцента) с небольшим сдвигом ±12° и вариациями
   светлоты/насыщенности, вплоть до почти-белого
   блика в одной точке — а не смесь фиолетового+розового+синего+циана. */
html[data-accent="holo-purple"]{
  --accent:#A78BFA;--accent-rgb:167,139,250;--accent-light:#C4B5FD;
  --holo-1:#2F16FE;--holo-2:#7953FF;--holo-3:#C9B3FB;--holo-4:#9653FF;--holo-5:#962BFF;
}
html[data-accent="holo-orange"]{
  --accent:#FB923C;--accent-rgb:251,146,60;--accent-light:#FDBA74;
  --holo-1:#D22C00;--holo-2:#FF5E10;--holo-3:#FBA96F;--holo-4:#FF8610;--holo-5:#E68C00;
}
html[data-accent="holo-red"]{
  --accent:#F87171;--accent-rgb:248,113,113;--accent-light:#FCA5A5;
  --holo-1:#EF0735;--holo-2:#FE3546;--holo-3:#F69999;--holo-4:#FE4635;--holo-5:#F84012;
}
html[data-accent="holo-green"]{
  --accent:#4ADE80;--accent-rgb:74,222,128;--accent-light:#86EFAC;
  --holo-1:#119927;--holo-2:#11D649;--holo-3:#5FE390;--holo-4:#11D66A;--holo-5:#12AC6A;
}
html[data-accent="holo-blue"]{
  --accent:#60A5FA;--accent-rgb:96,165,250;--accent-light:#93C5FD;
  --holo-1:#008DF4;--holo-2:#3291FF;--holo-3:#93BAFA;--holo-4:#326FFF;--holo-5:#0935FF;
}

/* Анимация линейного перелива слева направо через background-position. ВАЖНО про знак:
   при background-size > 100% формула CSS для процентной позиции — offset = (container_size
   - image_size) * (percent/100) — даёт ОТРИЦАТЕЛЬНУЮ разницу (container меньше image), значит
   чтобы реально сдвинуть картинку ВЛЕВО (offset отрицательный), процент должен быть
   ПОЛОЖИТЕЛЬНЫМ, а не отрицательным, как может показаться интуитивно. Первая версия этой
   анимации использовала отрицательные проценты (0% → -60%) в паре с background-repeat:
   no-repeat — из-за перепутанного знака картинка на самом деле уезжала ВПРАВО и полностью
   выезжала за пределы элемента, оставляя пустоту (баг, из-за которого голо-свотчи и активные
   кнопки выглядели наполовину чёрными/прозрачными). Правильное направление — 0% → 100%. */
@keyframes holoSweep{
  from{background-position:0% 0%;}
  to{background-position:100% 0%;}
}
/* ===== Применение голо-градиента к существующим акцентным поверхностям =====
   Вместо нового класса на каждом элементе (пришлось бы редактировать разметку во всех
   модулях-калькуляторах) — один override-блок по уже существующим селекторам, который
   активируется только когда выбран голо-акцент (родительский [data-accent^="holo-"]).
   Каждый селектор здесь — точная копия того места в файле, где обычно стоит
   background:var(--accent), плюс линейный градиент поверх и анимация сдвига позиции.
   Для обычных (не-holo) акцентов это правило вообще не применяется, так что
   производительность/вид плоских тем не меняется ни на бит. */
[data-accent^="holo-"] .badge,
[data-accent^="holo-"] .sidebtn:hover,
[data-accent^="holo-"] .sidebtn.active,
[data-accent^="holo-"] .toolbar .toolbtn.active,
[data-accent^="holo-"] .toolbtn.active,
[data-accent^="holo-"] .recycle-tab-btn.active,
[data-accent^="holo-"] .toast-undo-btn:hover,
[data-accent^="holo-"] .segment-thumb,
[data-accent^="holo-"] .upgrade-mat-chip.active,
[data-accent^="holo-"] .fab-expand{
  background-image:linear-gradient(100deg,var(--holo-1),var(--holo-2),var(--holo-3),var(--holo-4),var(--holo-5),var(--holo-1),var(--holo-2),var(--holo-3),var(--holo-4),var(--holo-5),var(--holo-1),var(--holo-2));
  background-size:200% 100%;
  background-repeat:no-repeat;
  animation:holoSweep var(--holo-anim-duration) ease-in-out infinite alternate;
}
/* .card.active и .settings-trigger используют border/box-shadow для акцента, а не
   background — вращающийся градиент по 2px рамке был бы визуально незаметен и избыточно
   сложен технически (border-image + анимация), поэтому вместо этого просто усиливаем
   свечение под голо-акцентом заметнее, чем у обычного плоского цвета. */
[data-accent^="holo-"] .card.active{
  box-shadow:0 0 30px rgba(var(--accent-rgb),.35);
}
[data-accent^="holo-"] .settings-trigger.settings-open{
  box-shadow:0 0 16px rgba(var(--accent-rgb),.5);
}

/* Светлая тема — светлый фон, тёмный текст, те же карточки/паттерны переструктурированы
   под инверсию яркости. Акцентный цвет остаётся тем же (var(--accent) не переопределяется
   здесь), т.к. цвет акцента и тема — два независимых выбора пользователя. Фон страницы
   заметно темнее карточек (#E4E7EC против белого) — иначе карточки визуально сливаются
   с фоном и тонкая граница #E5E7EB её одной не спасает, особенно на телефонных экранах
   при дневном свете. Плюс лёгкая тень на карточках (см. .card ниже) — она держит
   разделение даже там, где граница на глаз незаметна. */
html[data-theme="light"]{
  --bg-page:#E4E7EC;
  --bg-card:#FFFFFF;
  --bg-card-alt:#F3F4F6;
  --bg-sidebar:#FFFFFF;
  --bg-input:#F3F4F6;
  --bg-row-border:#E5E7EB;

  --border:#9AA3B2;
  --border-soft:#828C9E;

  --text-primary:#111827;
  --text-secondary:#4B5563;
  --text-muted:#6B7280;
  --text-footer:#9CA3AF;
}

/* Сверхтёмная (OLED) — чистый чёрный фон вместо тёмно-серого #0F1115, карточки почти
   сливаются с фоном (минимальная разница яркости), акцент становится единственным
   ярким пятном на экране — экономит батарею на OLED-экранах и даёт максимальный контраст. */
html[data-theme="oled"]{
  --bg-page:#000000;
  --bg-card:#0A0A0A;
  --bg-card-alt:#000000;
  --bg-sidebar:#000000;
  --bg-input:#0A0A0A;
  --bg-row-border:#1A1A1A;

  --border:#4A4A4A;
  --border-soft:#5E5E5E;

  --text-primary:#fff;
  --text-secondary:#A0A0A0;
  --text-muted:#707070;
  --text-footer:#666;
}

/* ===== Фоновая текстура =====
   Едва заметный hex-grid (шестигранная сетка) поверх фона страницы — намёк на металл/
   чертёж/индустриальную тему Rust, не отвлекает от плотного интерфейса калькуляторов.
   Цвет узора следует за выбранным акцентом (см. html[data-accent=...] body ниже) —
   CSS-переменные не работают внутри data:image/svg+xml URL, поэтому вместо одного
   правила с var(--accent) даём 5 готовых SVG, по одному на каждый акцент, с тем же
   путём и разным stroke. background-attachment:fixed — паттерн не скроллится вместе
   с контентом, остаётся статичным "фоном мира", как в играх с параллаксом. */
body{
  font-family:Inter,sans-serif;
  color:var(--text-primary);
  min-height:100vh;
  background-color:var(--bg-page);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='100' viewBox='0 0 56 100'%3E%3Cpath d='M28 0L56 16V50L28 66L0 50V16Z' fill='none' stroke='%238B5CF6' stroke-opacity='0.12' stroke-width='1.5'/%3E%3Cpath d='M28 34L56 50V84L28 100L0 84V50Z' fill='none' stroke='%238B5CF6' stroke-opacity='0.12' stroke-width='1.5'/%3E%3C/svg%3E");
  background-attachment:fixed;
  background-repeat:repeat;
}
html[data-accent="orange"] body{background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='100' viewBox='0 0 56 100'%3E%3Cpath d='M28 0L56 16V50L28 66L0 50V16Z' fill='none' stroke='%23F97316' stroke-opacity='0.12' stroke-width='1.5'/%3E%3Cpath d='M28 34L56 50V84L28 100L0 84V50Z' fill='none' stroke='%23F97316' stroke-opacity='0.12' stroke-width='1.5'/%3E%3C/svg%3E");}
html[data-accent="red"] body{background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='100' viewBox='0 0 56 100'%3E%3Cpath d='M28 0L56 16V50L28 66L0 50V16Z' fill='none' stroke='%23EF4444' stroke-opacity='0.12' stroke-width='1.5'/%3E%3Cpath d='M28 34L56 50V84L28 100L0 84V50Z' fill='none' stroke='%23EF4444' stroke-opacity='0.12' stroke-width='1.5'/%3E%3C/svg%3E");}
html[data-accent="green"] body{background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='100' viewBox='0 0 56 100'%3E%3Cpath d='M28 0L56 16V50L28 66L0 50V16Z' fill='none' stroke='%2322C55E' stroke-opacity='0.12' stroke-width='1.5'/%3E%3Cpath d='M28 34L56 50V84L28 100L0 84V50Z' fill='none' stroke='%2322C55E' stroke-opacity='0.12' stroke-width='1.5'/%3E%3C/svg%3E");}
html[data-accent="blue"] body{background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='100' viewBox='0 0 56 100'%3E%3Cpath d='M28 0L56 16V50L28 66L0 50V16Z' fill='none' stroke='%233B82F6' stroke-opacity='0.12' stroke-width='1.5'/%3E%3Cpath d='M28 34L56 50V84L28 100L0 84V50Z' fill='none' stroke='%233B82F6' stroke-opacity='0.12' stroke-width='1.5'/%3E%3C/svg%3E");}

/* Голографические варианты узора — та же hex-сетка, но оба path одного повторяющегося
   тайла окрашены в БЛИЗКИЕ оттенки одного тона (не в разные цвета), плюс поверх добавлен
   медленно плывущий слева направо linear-gradient слой на 6% непрозрачности из той же
   однотонной палитры, что и у кнопок/бейджей. Сама SVG-сетка не может быть анимированным
   градиентом (data-URI статичен), но overlay сверху даёт эффект лёгкой волны света,
   бегущей по всей странице, независимо от статичной геометрии сетки под ним; вторая
   линия сетки чуть темнее/светлее первой — намёк на глубину, а не смену цвета.
   background-size/position указаны для ОБОИХ слоёв (первое значение — для градиента,
   второе — auto для SVG, который должен просто повторяться на месте без сдвига). */
html[data-accent="holo-purple"] body{background-image:
    linear-gradient(100deg, rgba(47,22,254,.07), rgba(150,42,255,.07), rgba(201,179,251,.07), rgba(47,22,254,.07), rgba(150,42,255,.07), rgba(47,22,254,.07), rgba(150,42,255,.07), rgba(201,179,251,.07), rgba(47,22,254,.07), rgba(150,42,255,.07)),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='100' viewBox='0 0 56 100'%3E%3Cpath d='M28 0L56 16V50L28 66L0 50V16Z' fill='none' stroke='%238B5CF6' stroke-opacity='0.13' stroke-width='1.5'/%3E%3Cpath d='M28 34L56 50V84L28 100L0 84V50Z' fill='none' stroke='%23C9B3FB' stroke-opacity='0.11' stroke-width='1.5'/%3E%3C/svg%3E");
  background-size:200% 100%, auto;
  animation:holoSweep 22s ease-in-out infinite alternate;
  background-repeat:no-repeat,repeat;
  background-attachment:fixed,fixed;
}
html[data-accent="holo-orange"] body{background-image:
    linear-gradient(100deg, rgba(210,44,0,.07), rgba(255,94,16,.07), rgba(251,169,111,.07), rgba(210,44,0,.07), rgba(255,94,16,.07), rgba(210,44,0,.07), rgba(255,94,16,.07), rgba(251,169,111,.07), rgba(210,44,0,.07), rgba(255,94,16,.07)),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='100' viewBox='0 0 56 100'%3E%3Cpath d='M28 0L56 16V50L28 66L0 50V16Z' fill='none' stroke='%23F97316' stroke-opacity='0.13' stroke-width='1.5'/%3E%3Cpath d='M28 34L56 50V84L28 100L0 84V50Z' fill='none' stroke='%23FBA96F' stroke-opacity='0.11' stroke-width='1.5'/%3E%3C/svg%3E");
  background-size:200% 100%, auto;
  animation:holoSweep 22s ease-in-out infinite alternate;
  background-repeat:no-repeat,repeat;
  background-attachment:fixed,fixed;
}
html[data-accent="holo-red"] body{background-image:
    linear-gradient(100deg, rgba(239,7,53,.07), rgba(254,53,70,.07), rgba(246,153,153,.07), rgba(239,7,53,.07), rgba(254,53,70,.07), rgba(239,7,53,.07), rgba(254,53,70,.07), rgba(246,153,153,.07), rgba(239,7,53,.07), rgba(254,53,70,.07)),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='100' viewBox='0 0 56 100'%3E%3Cpath d='M28 0L56 16V50L28 66L0 50V16Z' fill='none' stroke='%23EF4444' stroke-opacity='0.13' stroke-width='1.5'/%3E%3Cpath d='M28 34L56 50V84L28 100L0 84V50Z' fill='none' stroke='%23F69999' stroke-opacity='0.11' stroke-width='1.5'/%3E%3C/svg%3E");
  background-size:200% 100%, auto;
  animation:holoSweep 22s ease-in-out infinite alternate;
  background-repeat:no-repeat,repeat;
  background-attachment:fixed,fixed;
}
html[data-accent="holo-green"] body{background-image:
    linear-gradient(100deg, rgba(17,153,39,.07), rgba(17,214,73,.07), rgba(95,227,144,.07), rgba(17,153,39,.07), rgba(17,214,73,.07), rgba(17,153,39,.07), rgba(17,214,73,.07), rgba(95,227,144,.07), rgba(17,153,39,.07), rgba(17,214,73,.07)),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='100' viewBox='0 0 56 100'%3E%3Cpath d='M28 0L56 16V50L28 66L0 50V16Z' fill='none' stroke='%2322C55E' stroke-opacity='0.13' stroke-width='1.5'/%3E%3Cpath d='M28 34L56 50V84L28 100L0 84V50Z' fill='none' stroke='%235FE390' stroke-opacity='0.11' stroke-width='1.5'/%3E%3C/svg%3E");
  background-size:200% 100%, auto;
  animation:holoSweep 22s ease-in-out infinite alternate;
  background-repeat:no-repeat,repeat;
  background-attachment:fixed,fixed;
}
html[data-accent="holo-blue"] body{background-image:
    linear-gradient(100deg, rgba(0,141,244,.07), rgba(50,145,255,.07), rgba(147,186,250,.07), rgba(0,141,244,.07), rgba(50,145,255,.07), rgba(0,141,244,.07), rgba(50,145,255,.07), rgba(147,186,250,.07), rgba(0,141,244,.07), rgba(50,145,255,.07)),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='100' viewBox='0 0 56 100'%3E%3Cpath d='M28 0L56 16V50L28 66L0 50V16Z' fill='none' stroke='%233B82F6' stroke-opacity='0.13' stroke-width='1.5'/%3E%3Cpath d='M28 34L56 50V84L28 100L0 84V50Z' fill='none' stroke='%2393BAFA' stroke-opacity='0.11' stroke-width='1.5'/%3E%3C/svg%3E");
  background-size:200% 100%, auto;
  animation:holoSweep 22s ease-in-out infinite alternate;
  background-repeat:no-repeat,repeat;
  background-attachment:fixed,fixed;
}

/* ===== Игровой шрифт для заголовков =====
   Oswald — узкое плотное начертание (изначально "газетный" стиль заголовков), уместно
   ложится в тему индустриального выживания Rust: строгое, чуть "военное" по духу, но
   без перегиба в стилизацию — кириллица читается чисто во всех буквах, включая Й/Щ/Ё
   (проверено визуально, у части других "military" шрифтов с этим есть проблемы).
   letter-spacing чуть шире нуля — у Oswald плотные буквы, небольшой трекинг возвращает
   воздух между ними и не даёт заголовкам "слипаться" при крупном размере. Тело текста
   (числа, описания, кнопки) остаётся на Inter — тот заметно читаемее в мелких размерах,
   Oswald для этого слишком узкий. */
h1,h2,h3,.title,.nav-title h2{
  font-family:'Oswald',Inter,sans-serif;
  font-weight:700;
  letter-spacing:.01em;
}
.container{width:min(1800px,94%);margin:auto;padding:40px 0}
header{margin-bottom:40px}
header h1{font-size:42px;font-weight:800}
header p{margin-top:10px;color:var(--text-secondary);font-size:18px}
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:22px}
.card{background:var(--bg-card);border:2px solid var(--border);border-radius:18px;padding:24px;cursor:pointer;transition:.25s}
/* На светлой теме тонкая граница ещё менее заметна на маленьком экране при ярком свете —
   добавляем мягкую тень, дублирующую эффект границы за счёт разницы в глубине, а не
   только в цвете. На тёмных темах увеличенного контраста --border (см. :root выше)
   уже достаточно, тень там не нужна. */
html[data-theme="light"] .card{box-shadow:0 1px 3px rgba(17,24,39,.06), 0 1px 2px rgba(17,24,39,.04)}
html[data-theme="light"] .card:hover{box-shadow:0 8px 20px rgba(17,24,39,.08)}
.card:hover{transform:translateY(-6px);border-color:var(--accent);box-shadow:0 0 25px rgba(var(--accent-rgb),.2)}
.icon{font-size:38px;margin-bottom:18px}
.title{font-size:22px;font-weight:700}
.description{margin-top:10px;color:var(--text-secondary);line-height:1.6}
footer{margin-top:50px;text-align:center;color:var(--text-footer)}
.badge{display:inline-block;margin-top:15px;padding:6px 12px;background:var(--accent);border-radius:50px;font-size:13px;font-weight:700}

/* Приветственная подсказка для новых посетителей (см. #onboardingBanner в index.html) —
   растягивается на всю ширину сетки карточек (grid-column:1/-1), а не сжимается в одну
   ячейку той же ширины, что и карточки калькуляторов. Показывается один раз через JS-флаг
   в localStorage — не должна навязчиво возвращаться после того, как человек её закрыл.
   Текст переводится через data-i18n атрибуты, как и остальная статичная разметка. */
.onboarding-banner{
grid-column:1/-1;
display:flex;
align-items:flex-start;
gap:16px;
background:rgba(var(--accent-rgb),.08);
border:1px solid rgba(var(--accent-rgb),.3);
border-radius:18px;
padding:20px 24px;
}
.onboarding-banner-icon{font-size:28px;flex-shrink:0}
.onboarding-banner-text{flex:1}
.onboarding-banner-text b{font-size:16px}
.onboarding-banner-text p{margin-top:6px;color:var(--text-secondary);line-height:1.6;font-size:14px}
@media(max-width:640px){
.onboarding-banner{flex-direction:column}
}

/* Компактная сворачиваемая подсказка внутри модуля-калькулятора (см. APP.UI.moduleHint
   в core.js) — тот же принцип, что у onboarding-banner на Главной (показать один раз,
   запомнить закрытие), но меньше и без отдельного заголовка: подсказка внутри модуля
   поясняет одну конкретную вещь ("как это работает"), а не весь сайт целиком, поэтому
   не нуждается в том же объёме текста и визуального веса. */
.module-hint{
display:flex;
align-items:flex-start;
gap:10px;
background:rgba(var(--accent-rgb),.07);
border:1px solid rgba(var(--accent-rgb),.25);
border-radius:12px;
padding:12px 14px;
margin-bottom:16px;
}
.module-hint-icon{font-size:16px;flex-shrink:0;line-height:1.5}
.module-hint-text{flex:1;font-size:13px;color:var(--text-secondary);line-height:1.5}
.module-hint-close{
background:none;border:none;color:var(--text-muted);cursor:pointer;
font-size:14px;line-height:1;padding:2px;flex-shrink:0;
-webkit-tap-highlight-color:transparent;
}
.module-hint-close:hover{color:var(--text-primary)}

header{
display:flex;
justify-content:space-between;
align-items:center;
gap:20px;
flex-wrap:wrap;
}
.top-actions{
display:flex;
gap:12px;
align-items:center;
}
.search{
background:var(--bg-card);
border:1px solid var(--border);
color:var(--text-primary);
padding:12px 16px;
border-radius:12px;
min-width:260px;
outline:none;
}
/* Выпадающий список результатов глобального поиска (см. #globalSearchResults в index.html) —
   появляется под полем поиска на Главной, когда запрос находит совпадения не только среди
   8 карточек модулей, но и внутри баз данных калькуляторов (предметы крафта/рейда/переработки).
   Работает на обоих языках — названия результатов и подписи модулей переводятся в core.js. */
.global-search-results{
position:absolute;
top:calc(100% + 8px);
left:0;
right:0;
max-height:360px;
overflow-y:auto;
background:var(--bg-card);
border:1px solid var(--border);
border-radius:12px;
box-shadow:0 12px 32px rgba(0,0,0,.4);
z-index:60;
}
.global-search-result-item{
display:flex;
justify-content:space-between;
align-items:center;
gap:10px;
padding:12px 16px;
cursor:pointer;
border-bottom:1px solid var(--border);
transition:.15s;
}
.global-search-result-item:last-child{border-bottom:none}
.global-search-result-item:hover,
.global-search-result-item.kbd-active{
background:rgba(var(--accent-rgb),.12);
}
.global-search-result-name{
font-size:14px;
color:var(--text-primary);
}
.global-search-result-module{
font-size:12px;
color:var(--accent);
white-space:nowrap;
}
.global-search-no-results{
padding:16px;
text-align:center;
color:var(--text-muted);
font-size:13px;
}
.sidebar{
position:fixed;
left:0;top:0;bottom:0;
width:88px;
background:var(--bg-sidebar);
border-right:1px solid var(--border);
display:flex;
flex-direction:column;
align-items:center;
padding:24px 0;
gap:14px;
overflow-y:auto;
}
/* Обёртка нужна, чтобы полоска-индикатор (см. .sidebtn-wrap::before) позиционировалась
   относительно слота кнопки, а не самой кнопки — так её можно расположить чуть левее
   от иконки, вплотную к краю сайдбара, как в Discord, без искажения формы самой иконки. */
.sidebtn-wrap{position:relative;display:flex;align-items:center;flex-shrink:0}
.sidebtn-wrap::before{
  content:'';
  position:absolute;left:-14px;top:50%;
  width:4px;height:0;
  border-radius:0 4px 4px 0;
  background:var(--text-primary);
  transform:translateY(-50%);
  transition:height .2s cubic-bezier(.4,0,.2,1), opacity .2s;
  opacity:0;
}
.sidebtn-wrap:hover::before{height:20px;opacity:.5}
.sidebtn-wrap:has(.sidebtn.active)::before{height:32px;opacity:1}
.sidebtn{
width:54px;height:54px;border-radius:16px;
display:flex;align-items:center;justify-content:center;
background:var(--bg-card);border:1px solid var(--border);
font-size:24px;
transition:background .2s, border-color .2s, border-radius .25s cubic-bezier(.4,0,.2,1), transform .2s;
flex-shrink:0;
}
/* border-radius растёт при hover/active (16px → 22px/26px) — тот же "квадрат размякает
   в скруглённый квадрат" эффект, что у иконок серверов в Discord, вместо простого
   изменения цвета/масштаба. Масштаб оставлен, но чуть мягче прежнего (1.08 → 1.05),
   чтобы не спорить с новым эффектом формы за внимание. */
.sidebtn:hover{background:var(--accent);border-radius:22px;transform:scale(1.05)}
.sidebtn.active{background:var(--accent);border-color:var(--accent);border-radius:26px}
/* .sidebtn фон совпадает с .card (белый) и сидит на белом .sidebar — на тёмных темах
   разница цветов сама разделяет их, на светлой нужна тень, как и у .card выше. */
html[data-theme="light"] .sidebtn{box-shadow:0 1px 3px rgba(17,24,39,.08)}
.container{margin-left:120px}
@media(max-width:768px){
.sidebar{display:none}
.container{margin-left:auto}
.search{min-width:100%}
/* background-attachment:fixed известен как источник лагов при скролле на части мобильных
   браузеров (особенно старый iOS Safari) — на узких экранах переключаем на scroll,
   визуальная разница почти незаметна, а плавность скролла важнее. */
body{background-attachment:scroll}
}


.content-panel{
margin-top:34px;
background:var(--bg-card-alt);
border:2px solid var(--border);
border-radius:18px;
padding:28px;
animation:fade .35s cubic-bezier(.22,1,.36,1);
/* Слабое постоянное акцентное свечение — отличает открытую панель калькулятора от
   рядового статичного блока, читается как "активное окно" не только по border,
   но и по лёгкому ореолу. Заметно слабее hover-свечения карточек (.15 против .2
   alpha у .card:hover), т.к. это состояние держится постоянно, а не на секунду. */
box-shadow:0 0 40px rgba(var(--accent-rgb),.08);
}
.content-panel h2{font-size:28px;margin-bottom:10px}
.content-panel p{color:var(--text-secondary);line-height:1.7}
.card.active{
border-color:var(--accent);
box-shadow:0 0 25px rgba(var(--accent-rgb),.25);
}
/* ===== Toast-уведомления =====
   Стек карточек сверху по центру (не пересекается с FAB-кнопками, которые всегда
   снизу справа). Каждый toast имеет тип (success/error/info) со своей иконкой и
   цветным акцентом слева, плюс тающую полоску снизу — видно, сколько времени
   осталось до автоматического закрытия. */
.toast-stack{
  position:fixed;
  top:20px;left:50%;
  transform:translateX(-50%);
  z-index:1200;
  display:flex;
  flex-direction:column;
  gap:10px;
  align-items:center;
  pointer-events:none;
  width:min(420px,calc(100vw - 32px));
}
.toast-item{
  pointer-events:auto;
  position:relative;
  display:flex;
  align-items:flex-start;
  gap:10px;
  width:100%;
  background:var(--bg-card);
  border:1px solid var(--border);
  border-left:3px solid var(--accent);
  padding:13px 16px 15px;
  border-radius:12px;
  box-shadow:0 8px 24px rgba(0,0,0,.35);
  overflow:hidden;
  opacity:0;
  transform:translateY(-16px) scale(.96);
  transition:opacity .25s cubic-bezier(.34,1.56,.64,1), transform .25s cubic-bezier(.34,1.56,.64,1);
}
.toast-item.show{opacity:1;transform:translateY(0) scale(1)}
.toast-item.hide{opacity:0;transform:translateY(-10px) scale(.96)}
.toast-item.type-success{border-left-color:var(--success)}
.toast-item.type-error{border-left-color:var(--danger)}
.toast-item.type-info{border-left-color:var(--accent)}
.toast-icon{font-size:18px;line-height:1;flex-shrink:0;margin-top:1px}
.toast-text{font-size:14px;line-height:1.4;flex:1}
.toast-close{
  background:none;border:none;color:var(--text-muted);cursor:pointer;
  font-size:16px;line-height:1;padding:2px;flex-shrink:0;
  -webkit-tap-highlight-color:transparent;
}
.toast-close:hover{color:var(--text-primary)}
.toast-close:focus,.toast-close:focus-visible{outline:none}
.toast-undo-btn{
  background:none;border:1px solid var(--accent);color:var(--accent);
  cursor:pointer;font-size:12px;font-weight:700;
  padding:4px 10px;border-radius:7px;flex-shrink:0;
  -webkit-tap-highlight-color:transparent;
  transition:.15s;
}
.toast-undo-btn:hover{background:var(--accent);color:#fff}
.toast-progress{
  position:absolute;left:0;bottom:0;height:2px;
  background:currentColor;opacity:.5;
  animation:toastShrink linear forwards;
}
.toast-item.type-success .toast-progress{color:var(--success)}
.toast-item.type-error .toast-progress{color:var(--danger)}
.toast-item.type-info .toast-progress{color:var(--accent)}
@keyframes toastShrink{
  from{width:100%}
  to{width:0%}
}
@media (max-width:640px){
  .toast-stack{top:12px}
}
@keyframes fade{
from{opacity:0;transform:translateY(12px)}
to{opacity:1;transform:none}
}

.page{display:none;animation:fade .35s cubic-bezier(.22,1,.36,1)}
.page.active{display:block}
.nav-title{display:flex;justify-content:space-between;align-items:center;margin-bottom:18px}
.back-btn{
background:var(--accent);border:none;color:#fff;padding:10px 16px;
border-radius:10px;cursor:pointer;font-weight:600;display:none}
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:16px;margin-top:24px}
.stat{
background:var(--bg-card);border:1px solid var(--border);border-radius:14px;padding:18px}
.stat h3{font-size:14px;color:var(--text-secondary);margin-bottom:8px}
.stat b{font-size:24px}

.toolbar{display:flex;gap:12px;margin:20px 0;flex-wrap:wrap}
.toolbtn{
background:var(--bg-card);border:1px solid var(--border);color:var(--text-primary);
padding:10px 16px;border-radius:10px;cursor:pointer;transition:.2s}
.toolbtn:hover{border-color:var(--accent)}
.toolbar .toolbtn.active{background:var(--accent);border-color:var(--accent);color:#fff}
.toolbtn.active{background:var(--accent);border-color:var(--accent);color:#fff}
.searchmark{outline:2px solid var(--accent)}


/* Desktop two-column layout */
@media (min-width:1100px){
  html,body{
    height:100%;
    overflow:hidden;
  }
  .container{
    display:grid;
    grid-template-columns:420px 1fr;
    grid-template-rows:auto 1fr auto;
    grid-template-areas:
      "header header"
      "grid   panel"
      "footer footer";
    gap:18px;
    height:100vh;
    padding-top:14px;
    padding-bottom:14px;
  }
  header{margin-bottom:0}
  header h1{font-size:32px}
  header p{font-size:15px}
  footer{margin-top:0;font-size:13px}
  header{grid-area:header}
  footer{grid-area:footer}
  .grid{
    grid-area:grid;
    width:auto;
    grid-template-columns:repeat(2,1fr);
    min-height:0;
    overflow-y:auto;
    -webkit-overflow-scrolling:touch;
  }
  .content-panel{
    grid-area:panel;
    margin-top:0;
    min-width:0;
    min-height:0;
    overflow-y:auto;
    -webkit-overflow-scrolling:touch;
  }
  /* Скроллбары в теме сайта: серая дорожка, оранжевый ползунок */
  .grid,.content-panel{
    scrollbar-width:thin;
    scrollbar-color:var(--accent) var(--bg-card);
  }
  .grid::-webkit-scrollbar,
  .content-panel::-webkit-scrollbar{
    width:8px;
  }
  .grid::-webkit-scrollbar-track,
  .content-panel::-webkit-scrollbar-track{
    background:var(--bg-card);
    border-radius:8px;
  }
  .grid::-webkit-scrollbar-thumb,
  .content-panel::-webkit-scrollbar-thumb{
    background:var(--accent);
    border-radius:8px;
  }
  .grid::-webkit-scrollbar-thumb:hover,
  .content-panel::-webkit-scrollbar-thumb:hover{
    background:var(--accent-light);
  }
  .back-btn{
    display:none !important;
  }
}


/* Craft desktop split */
@media (min-width:1100px){
.craft-layout{display:grid;grid-template-columns:minmax(380px,1fr) 380px;gap:24px;align-items:start}
.craft-left{min-width:0}
.craft-right{position:sticky;top:30px}
}

/* Ещё шире экраны — даём панели больше воздуха вместо пустоты по бокам */
@media (min-width:1500px){
  .container{
    grid-template-columns:460px 1fr;
  }
  .craft-layout{grid-template-columns:minmax(420px,1fr) 420px}
}

/* Мобильный полноэкранный режим калькулятора: когда открыт любой модуль (не "Главная"),
   панель разворачивается на весь экран поверх карточек — не нужно листать вниз мимо списка. */
@media (max-width:1099px){
  .content-panel.fullscreen-mobile{
    position:fixed;
    inset:0;
    z-index:1000;
    margin:0;
    border-radius:0;
    border:none;
    overflow-y:auto;
    -webkit-overflow-scrolling:touch;
    padding:0 20px 40px;
  }
  .content-panel.fullscreen-mobile .nav-title{
    position:sticky;
    top:0;
    z-index:5;
    background:var(--bg-card-alt);
    padding:16px 0;
    margin-bottom:8px;
    border-bottom:1px solid var(--border);
  }
  .content-panel.fullscreen-mobile .back-btn{
    display:inline-block !important;
  }
}


/* ===== Переработчик (Recycler) ===== */

.recycle-wrap{display:flex;flex-direction:column;gap:16px}

/* Сетка карточек предметов: 1 колонка на мобиле, авто-заполнение плитками на широких экранах */
.recycle-grid{
  display:grid;
  grid-template-columns:1fr;
  gap:10px;
}
@media (min-width:700px){
  .recycle-grid{grid-template-columns:repeat(2,1fr)}
}
@media (min-width:1500px){
  .recycle-grid{grid-template-columns:repeat(2,1fr)}
}

.recycle-card{
  background:var(--bg-card);
  border:1px solid var(--border);
  border-radius:14px;
  padding:14px;
  display:flex;
  flex-direction:column;
  gap:10px;
  transition:border-color .2s, transform .15s;
  animation:cardIn .25s ease;
}
.recycle-card:hover{border-color:var(--border-soft)}
.recycle-card.has-qty{border-color:var(--accent);box-shadow:0 0 0 1px rgba(var(--accent-rgb),.15)}

@keyframes cardIn{
  from{opacity:0;transform:translateY(6px)}
  to{opacity:1;transform:none}
}
@keyframes qtyPop{
  0%{transform:scale(1)}
  40%{transform:scale(1.25)}
  100%{transform:scale(1)}
}
.qty-pop{animation:qtyPop .25s ease}

.recycle-card-head{display:flex;justify-content:space-between;align-items:flex-start;gap:10px}
.recycle-card-title{font-weight:600;font-size:15px;line-height:1.3}
.recycle-card-cat{font-size:11px;color:var(--text-muted);margin-top:2px}

.recycle-chips{display:flex;flex-wrap:wrap;gap:6px}
.recycle-chip{
  display:inline-flex;align-items:center;gap:5px;
  background:var(--bg-card-alt);border:1px solid var(--border);
  border-radius:20px;padding:4px 10px;font-size:12px;white-space:nowrap;
}
.recycle-chip.guaranteed{border-color:rgba(34,197,94,.35);color:#86efac}
.recycle-chip.chance{border-color:rgba(234,179,8,.35);color:#fde68a}
.recycle-chip .chip-amt{font-weight:700;color:#fff}

.recycle-shredder-tag{
  display:inline-flex;align-items:center;gap:4px;
  font-size:11px;color:var(--accent);background:rgba(var(--accent-rgb),.1);
  border:1px solid rgba(var(--accent-rgb),.3);border-radius:20px;padding:3px 9px;
  align-self:flex-start;
}

.recycle-counter-row{display:flex;justify-content:flex-end;align-items:center;gap:10px;margin-top:auto}
.recycle-counter{display:flex;align-items:center;gap:8px}
.recycle-counter button{
  width:34px;height:34px;border-radius:10px;
  background:var(--bg-card-alt);border:1px solid var(--border);color:var(--text-primary);
  font-size:18px;line-height:1;cursor:pointer;transition:.2s;
  display:flex;align-items:center;justify-content:center;
}
.recycle-counter button:hover{border-color:var(--accent);background:rgba(var(--accent-rgb),.08)}
.recycle-counter b{min-width:28px;text-align:center;font-size:16px}

/* Переключатель режима переработчика — крупные плитки */
/* Результат: карточка ресурса с иконкой */
.result-resource-row{
  display:flex;justify-content:space-between;align-items:center;
  padding:9px 0;border-bottom:1px solid var(--bg-row-border);
}
.result-resource-row:last-child{border-bottom:none}
.result-resource-name{display:flex;align-items:center;gap:8px;font-size:14px}
.result-resource-val{font-weight:700;font-size:15px}

/* Мобильные вкладки: Предметы / Результат */
.recycle-mobile-tabs{display:none;gap:8px;margin-bottom:4px}
@media (max-width:1099px){
  .recycle-mobile-tabs{display:flex}
  .recycle-pane{display:none}
  .recycle-pane.active-pane{display:block}
}
@media (min-width:1100px){
  .recycle-pane-items,.recycle-pane-result{display:block !important}
}
.recycle-tab-btn{
  flex:1;padding:10px;border-radius:10px;
  background:var(--bg-card-alt);border:1px solid var(--border);color:var(--text-secondary);
  font-weight:600;cursor:pointer;transition:.2s;position:relative;
}
.recycle-tab-btn.active{background:var(--accent);border-color:var(--accent);color:#fff}
.recycle-tab-badge{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:18px;height:18px;padding:0 5px;margin-left:6px;
  background:rgba(255,255,255,.25);border-radius:20px;font-size:11px;
}

/* ===== Универсальное пустое состояние =====
   Используется везде, где список/результат пуст: нет избранного, нет совпадений
   поиска, ничего не выбрано и т.д. Иконка мягко покачивается — не механическая
   заглушка, а живой элемент интерфейса, который сразу считывается взглядом. */
.empty-state{
  padding:34px 20px;
  text-align:center;
  color:var(--text-muted);
  animation:emptyStateIn .3s ease;
}
.empty-state .empty-icon{
  font-size:38px;
  margin-bottom:12px;
  display:block;
  animation:emptyIconFloat 2.6s ease-in-out infinite;
}
.empty-state .empty-title{
  font-size:15px;
  font-weight:700;
  color:var(--text-secondary);
  margin-bottom:4px;
}
.empty-state .empty-desc{
  font-size:13px;
  line-height:1.5;
  max-width:320px;
  margin:0 auto;
}
@keyframes emptyStateIn{
  from{opacity:0;transform:translateY(6px)}
  to{opacity:1;transform:none}
}
@keyframes emptyIconFloat{
  0%,100%{transform:translateY(0)}
  50%{transform:translateY(-5px)}
}
/* Совместимость со старой разметкой (.recycle-empty), которая ещё встречается в
   нескольких местах кода — работает идентично .empty-state. */
.recycle-empty{padding:30px 16px;text-align:center;color:var(--text-muted);animation:emptyStateIn .3s ease}
.recycle-empty .empty-icon{font-size:34px;margin-bottom:10px;display:block;animation:emptyIconFloat 2.6s ease-in-out infinite}

/* Звёздочка избранного на карточке */
.recycle-fav-btn{
  position:relative;
  background:none;border:none;cursor:pointer;
  padding:2px;flex-shrink:0;
  -webkit-tap-highlight-color:transparent;
}
.recycle-fav-btn:focus,.recycle-fav-btn:focus-visible{outline:none}
.fav-star{
  display:inline-block;
  font-size:19px;line-height:1;
  color:var(--text-muted);transition:transform .15s;
}
.recycle-fav-btn:hover .fav-star{transform:scale(1.15)}
.recycle-fav-btn.is-fav .fav-star{color:var(--accent)}

/* Анимация "взрыва" при добавлении в избранное — звезда резко вырастает, чуть
   поворачивается и возвращается на место (пружинистый эффект), плюс вокруг неё
   разлетаются короткоживущие искры-частицы (см. .fav-spark, генерируются в JS).
   Применяется ТОЛЬКО к .fav-star (сама звезда), не к кнопке-контейнеру — иначе
   вместе со звездой скачет вся квадратная область вокруг неё, что выглядит грубо. */
@keyframes favPop{
  0%{transform:scale(1) rotate(0deg)}
  35%{transform:scale(1.5) rotate(-12deg)}
  60%{transform:scale(.85) rotate(6deg)}
  100%{transform:scale(1) rotate(0deg)}
}
.fav-pop{animation:favPop .45s cubic-bezier(.34,1.56,.64,1)}

.fav-spark-wrap{
  position:absolute;inset:0;pointer-events:none;
  overflow:visible;
}
.fav-spark{
  position:absolute;top:50%;left:50%;
  width:5px;height:5px;border-radius:50%;
  background:var(--accent);
  transform:translate(-50%,-50%);
  animation:favSpark .55s ease-out forwards;
}
@keyframes favSpark{
  0%{opacity:1;transform:translate(-50%,-50%) translate(0,0) scale(1)}
  100%{opacity:0;transform:translate(-50%,-50%) translate(var(--sx),var(--sy)) scale(.3)}
}

/* ===== Универсальный сегментированный переключатель (2-4 состояния) =====
   Используется везде, где нужно выбрать один режим из нескольких:
   Переработчик (Все/Частые/Избранное, Монумент/Safe Zone),
   Калькулятор крафта и Калькулятор ресурсов (режим пороха), и т.д.
   Плавающий индикатор .segment-thumb физически едет между кнопками (transform),
   создавая эффект "переливания", а не просто мгновенно меняет фон. */
.segment-switch{
  position:relative;
  display:flex;gap:3px;padding:4px;margin-bottom:16px;
  background:var(--bg-page);border:1px solid var(--border);border-radius:12px;
}
.segment-thumb{
  position:absolute;top:4px;bottom:4px;left:4px;
  border-radius:9px;
  background:linear-gradient(135deg,var(--accent),var(--accent-light));
  box-shadow:0 2px 10px rgba(var(--accent-rgb),.4);
  transition:
    transform .38s cubic-bezier(.34,1.56,.64,1),
    width .38s cubic-bezier(.34,1.56,.64,1),
    height .38s cubic-bezier(.34,1.56,.64,1);
  transform-origin:center;
  z-index:0;
  will-change:transform;
}
/* "Желейный" squash&stretch на время движения: сжимаемся по одной оси, растягиваемся
   по другой — короткий, живой эффект, а не просто механическое скольжение блока. */
.segment-switch:not(.column-mode) .segment-thumb.thumb-moving{
  transform:var(--thumb-transform) scaleX(1.08) scaleY(.9);
}
.segment-switch.column-mode .segment-thumb.thumb-moving{
  transform:var(--thumb-transform) scaleY(1.08) scaleX(.96);
}
.segment-btn{
  position:relative;z-index:1;
  flex:1;padding:9px 10px;border:none;border-radius:9px;
  background:transparent;color:var(--text-secondary);font-size:13px;font-weight:600;
  cursor:pointer;transition:color .2s;
  white-space:nowrap;
  text-align:center;
}
.segment-btn:hover{color:#fff}
.segment-btn.active{color:#fff}

/* На узких экранах подписи в 3+ кнопках физически не влезают в один горизонтальный ряд —
   вместо скролла (который прятал часть текста и путал пользователя) переключатель
   становится вертикальным столбцом: каждая кнопка на всю ширину, свободный перенос текста.
   Thumb в этом режиме едет по вертикали (translateY) и занимает всю ширину контейнера. */
@media (max-width:640px){
  .segment-switch{flex-direction:column}
  .segment-btn{
    white-space:normal;
    text-align:left;
    padding:12px 14px;
  }
}

.recycle-subheading{
  font-size:11px;text-transform:uppercase;letter-spacing:.06em;
  color:var(--text-muted);margin-bottom:8px;
}

/* Крупный вариант сегмента (иконка+подпись+процент в столбик) — для Монумент/Safe Zone */
.segment-switch.segment-lg .segment-btn{
  display:flex;flex-direction:column;align-items:center;gap:4px;
  padding:12px 8px;
}
.segment-switch.segment-lg .segment-btn .mode-icon{font-size:22px}
.segment-switch.segment-lg .segment-btn .mode-pct{font-size:12px;opacity:.75}

/* Список выбранных предметов в панели результата */
.recycle-selected-row{
  display:flex;justify-content:space-between;align-items:center;gap:10px;
  padding:8px 0;border-bottom:1px solid var(--bg-row-border);
}
.recycle-selected-row:last-child{border-bottom:none}

/* ===== Универсальная строка списка с разделителем (Discord-style) =====
   Тонкая линия между элементами списка вместо оборачивания каждой строки в отдельную
   карточку с рамкой — более лёгкий, "плоский" паттерн для плотных списков (предметов,
   логов, настроек), где рамка на каждой строке была бы избыточной. Последняя строка
   без границы снизу, чтобы список не заканчивался повисшей линией перед следующим
   блоком. Используется как базовый класс — можно комбинировать с flex/grid внутри. */
.list-row{
  padding:10px 0;
  border-bottom:1px solid var(--bg-row-border);
}
.list-row:last-child{border-bottom:none}
.list-row:hover{background:rgba(var(--accent-rgb),.04)}
.recycle-selected-name{font-size:13px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.recycle-selected-row .recycle-counter button{width:26px;height:26px;font-size:15px;border-radius:8px}
.recycle-selected-row .recycle-counter b{font-size:13px;min-width:18px}
.recycle-remove-btn{
  background:none;border:none;color:var(--text-muted);cursor:pointer;
  font-size:15px;padding:4px;transition:color .15s;
}
.recycle-remove-btn:hover{color:var(--danger)}

/* ===== Прогресс-бар "есть / нужно" (режим "У меня есть" в калькуляторе крафта) =====
   Тонкая полоска под каждым полем ввода — заполняется от 0 до 100% по соотношению
   введённого количества к тому, что реально требуется. Цвет плавно переходит от красного
   (сильный дефицит) через жёлтый к зелёному (хватает) — это даёт мгновенное визуальное
   считывание без необходимости вчитываться в цифры, дополняя текстовый статус-бейдж снизу. */
.have-progress-track{
  height:4px;
  border-radius:2px;
  background:var(--bg-page);
  margin-top:6px;
  overflow:hidden;
}
.have-progress-fill{
  height:100%;
  width:0%;
  border-radius:2px;
  background:var(--danger);
  transition:width .35s cubic-bezier(.4,0,.2,1), background-color .35s ease;
}

/* ===== Skeleton loading (плейсхолдеры на время тяжёлого рендера) =====
   Бегущий градиент-блик создаёт иллюзию "загрузки контента", а не мёртвой заглушки.
   Форма карточки повторяет .recycle-card, чтобы переход к реальному контенту не дёргал
   раскладку — высота и отступы примерно совпадают. */
.skeleton-card{
  background:var(--bg-card);
  border:1px solid var(--border);
  border-radius:14px;
  padding:14px;
  display:flex;
  flex-direction:column;
  gap:10px;
  min-height:118px;
}
.skeleton-line{
  height:14px;
  border-radius:6px;
  background:linear-gradient(90deg,var(--bg-row-border) 25%,#2e3340 50%,var(--bg-row-border) 75%);
  background-size:200% 100%;
  animation:skeletonShimmer 1.4s ease-in-out infinite;
}
.skeleton-title{width:70%;height:16px}
.skeleton-chip{width:85%}
@keyframes skeletonShimmer{
  0%{background-position:200% 0}
  100%{background-position:-200% 0}
}

/* ===== Калькулятор апгрейда: выбор материалов "Из / В" ===== */
.upgrade-material-grid{
  display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:24px;
}
@media (max-width:600px){
  .upgrade-material-grid{grid-template-columns:1fr}
}
.upgrade-material-col{
  background:var(--bg-card);border:1px solid var(--border);border-radius:14px;padding:16px;
}
.upgrade-chip-list{display:flex;flex-wrap:wrap;gap:8px}
.upgrade-mat-chip{
  display:flex;align-items:center;gap:7px;
  padding:10px 14px;border-radius:11px;
  background:var(--bg-card-alt);border:1px solid var(--border);color:var(--text-secondary);
  font-size:14px;font-weight:600;cursor:pointer;
  transition:border-color .2s, background .2s, transform .12s, color .2s;
}
.upgrade-mat-chip .mat-icon{font-size:17px}
.upgrade-mat-chip:hover{border-color:var(--accent);color:#fff}
.upgrade-mat-chip.active{
  background:linear-gradient(135deg,var(--accent),var(--accent-light));
  border-color:var(--accent);color:#fff;
  box-shadow:0 3px 12px rgba(var(--accent-rgb),.35);
  transform:translateY(-1px);
}

/* ===== Плавающая круглая кнопка (FAB), которая раскрывается с подписью при наведении =====
   Используется для "План рейда" и подобных вспомогательных панелей. Позиционирование
   через безопасные отступы (env safe-area) и min(), чтобы никогда не вылезать за экран
   даже на самых узких телефонах или с вырезом/чёлкой снизу. */
.fab-expand{
  position:fixed;
  right:max(20px, env(safe-area-inset-right, 20px));
  bottom:max(20px, env(safe-area-inset-bottom, 20px));
  height:56px;min-width:56px;max-width:calc(100vw - 40px);
  border-radius:28px;
  background:linear-gradient(135deg,var(--accent),var(--accent-light));
  border:none;color:#fff;
  cursor:pointer;z-index:900;
  display:inline-flex;align-items:center;
  padding:0;
  box-shadow:0 6px 20px rgba(var(--accent-rgb),.4);
  transition:min-width .3s cubic-bezier(.4,0,.2,1), box-shadow .2s, transform .15s;
  white-space:nowrap;
}
.fab-expand:hover,.fab-expand:focus-visible{
  min-width:180px;
  box-shadow:0 8px 26px rgba(var(--accent-rgb),.55);
}
.fab-expand:active{transform:scale(.96)}
.fab-expand .fab-icon{
  flex-shrink:0;width:56px;height:56px;
  display:flex;align-items:center;justify-content:center;
  font-size:24px;
}
.fab-expand .fab-label{
  max-width:0;opacity:0;overflow:hidden;
  font-size:14px;font-weight:700;
  transition:max-width .3s cubic-bezier(.4,0,.2,1), opacity .2s .05s;
  padding-right:0;
  white-space:nowrap;
}
.fab-expand:hover .fab-label,.fab-expand:focus-visible .fab-label{
  max-width:220px;opacity:1;padding-right:20px;
}
.fab-expand.fab-touch-open{min-width:fit-content}
.fab-expand.fab-touch-open .fab-label{max-width:220px;opacity:1;padding-right:20px}

/* Поле ручного ввода количества (печи, крафт-счётчики) — выглядит как число, а не как обычный текстовый инпут */
.smelt-count-input{
  font-size:24px;font-weight:700;text-align:center;
  width:70px;background:var(--bg-card-alt);border:1px solid var(--border);color:var(--text-primary);
  border-radius:10px;padding:8px 4px;
}
.smelt-count-input:focus{outline:none;border-color:var(--accent)}

/* Плавающая круглая кнопка (FAB) — резервируем место снизу страницы, чтобы она не перекрывала
   последний элемент контента (например, кнопку "Скопировать" в апгрейде или итог в рейде) */
body:has(.fab-expand) .content-panel{padding-bottom:90px}

/* Поле ввода количества в счётчике крафта — заменяет прежний <b>, теперь редактируемое */
.craft-count{
  width:52px;text-align:center;font-weight:700;font-size:15px;
  background:var(--bg-card-alt);border:1px solid var(--border);color:var(--text-primary);
  border-radius:8px;padding:6px 2px;
}
.craft-count:focus{outline:none;border-color:var(--accent)}
.fab-badge{
  position:absolute;top:-4px;right:-4px;
  min-width:24px;height:24px;padding:0 6px;
  border-radius:12px;background:#fff;color:var(--accent);
  font-size:12px;font-weight:800;
  display:flex;align-items:center;justify-content:center;
  border:2px solid var(--bg-card-alt);
  z-index:2;
  box-shadow:0 2px 6px rgba(0,0,0,.3);
}
@media (max-width:1099px){
  /* На мобиле подпись по hover не сработает (нет курсора) — раскрываем по долгому нажатию
     через JS (см. raid.js), здесь просто не даём подписи мешать при обычных тапах. */
  .fab-expand .fab-label{transition:max-width .3s cubic-bezier(.4,0,.2,1), opacity .15s}
}



/* ===== Панель настроек (кнопка-шестерёнка в шапке) =====
   Заменяет прежние отдельно стоящие .badge (версия) и .lang-switch — теперь оба живут
   внутри одной панели вместе с выбором акцентного цвета и темы. Кнопка-шестерёнка —
   единственный видимый элемент в шапке, всё остальное открывается по клику в drawer
   справа (тот же паттерн подъезжающей панели, что уже используется в toast-stack/FAB,
   не вводим новый визуальный язык). На мобиле drawer растягивается на всю ширину. */
.settings-trigger{
  width:44px;height:44px;border-radius:12px;
  background:var(--bg-card);border:1px solid var(--border);
  color:var(--text-secondary);font-size:19px;
  display:flex;align-items:center;justify-content:center;
  cursor:pointer;transition:.2s;flex-shrink:0;
}
.settings-trigger:hover{border-color:var(--accent);color:var(--text-primary)}
.settings-trigger:active{transform:scale(.92)}
/* Поворот шестерёнки происходит осознанно — когда панель настроек реально открыта
   (класс settings-open навешивается на trigger в JS вместе с открытием drawer),
   а не на каждый hover, который выглядел как случайное дёрганье при наведении. */
.settings-trigger.settings-open{border-color:var(--accent);color:var(--accent);transform:rotate(90deg)}

.settings-overlay{
  position:fixed;inset:0;
  background:rgba(0,0,0,.55);
  z-index:1300;
  opacity:0;pointer-events:none;
  transition:opacity .25s ease;
}
.settings-overlay.open{opacity:1;pointer-events:auto}

.settings-drawer{
  position:fixed;top:0;right:0;bottom:0;
  width:min(380px,100vw);
  background:var(--bg-card);
  border-left:1px solid var(--border);
  z-index:1301;
  display:flex;flex-direction:column;
  transform:translateX(100%);
  transition:transform .3s cubic-bezier(.4,0,.2,1);
  overflow-y:auto;
}
.settings-drawer.open{transform:translateX(0)}

.settings-header{
  display:flex;align-items:center;justify-content:space-between;
  padding:22px 24px;border-bottom:1px solid var(--border);
  flex-shrink:0;
}
.settings-header h3{font-size:19px}
.settings-close{
  width:36px;height:36px;border-radius:10px;border:1px solid var(--border);
  background:var(--bg-card-alt);color:var(--text-secondary);
  font-size:16px;cursor:pointer;transition:.2s;
  display:flex;align-items:center;justify-content:center;
}
.settings-close:hover{border-color:var(--accent);color:var(--text-primary)}

.settings-body{padding:22px 24px;display:flex;flex-direction:column;gap:28px}
.settings-section-label{
  font-size:12px;text-transform:uppercase;letter-spacing:.06em;
  color:var(--text-muted);margin-bottom:12px;font-weight:700;
}

/* Кружки выбора акцентного цвета — сам кружок залит соответствующим цветом (не через
   var(--accent), т.к. все 5 должны быть видны одновременно вне зависимости от того,
   какой сейчас активен), с кольцом-обводкой и галочкой на активном варианте. */
.accent-swatches{display:flex;gap:14px;flex-wrap:wrap}
.accent-swatch{
  width:42px;height:42px;border-radius:50%;
  cursor:pointer;border:2px solid transparent;
  display:flex;align-items:center;justify-content:center;
  transition:transform .15s, border-color .15s;
  position:relative;
}
.accent-swatch:hover{transform:scale(1.1)}
.accent-swatch.active{border-color:var(--text-primary)}
.accent-swatch.active::after{
  content:'✓';color:#fff;font-size:16px;font-weight:800;
  text-shadow:0 1px 3px rgba(0,0,0,.5);
}
.accent-swatch[data-accent-value="purple"]{background:#8B5CF6}
.accent-swatch[data-accent-value="orange"]{background:#F97316}
.accent-swatch[data-accent-value="red"]{background:#EF4444}
.accent-swatch[data-accent-value="green"]{background:#22C55E}
.accent-swatch[data-accent-value="blue"]{background:#3B82F6}

/* Подпись "Голографические" — чуть отступлена сверху от предыдущего ряда обычных
   свотчей, тот же визуальный вес что и у settings-section-label выше по разметке. */
.holo-label{margin-top:18px}

/* Голо-свотчи в самой панели настроек — тот же плывущий слева направо linear-gradient,
   что и в остальном интерфейсе (см. holoSweep выше). Свотчи — витрина эффекта: если
   здесь заливка статична, человек не видит переливания до того, как уже выбрал акцент,
   и решение "нравится/не нравится" принимается вслепую. Каждый свотч анимируется тем же
   @keyframes holoSweep, но с собственным animation-delay (см. :nth-child ниже) — так
   все 5 плывут не синхронно в такт, а слегка вразнобой, что выглядит как живой перелив,
   а не как один узор, механически повторённый 5 раз. background-size:300% растягивает
   градиент в 3 раза шире круглого свотча — на маленькой площади (42px) без растяжки волна
   пробегала бы слишком быстро и резко, как мигание, а не плавный перелив. */
.accent-swatch-holo{
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.25);
  background-size:200% 100%;
  background-repeat:no-repeat;
  animation:holoSweep 4s ease-in-out infinite alternate;
}
.accent-swatch-holo:nth-child(2){animation-delay:-.8s}
.accent-swatch-holo:nth-child(3){animation-delay:-1.6s}
.accent-swatch-holo:nth-child(4){animation-delay:-2.4s}
.accent-swatch-holo:nth-child(5){animation-delay:-3.2s}
.accent-swatch[data-accent-value="holo-purple"]{background-image:linear-gradient(100deg,#2F16FE,#7953FF,#C9B3FB,#9653FF,#962BFF,#2F16FE,#7953FF,#C9B3FB,#9653FF,#962BFF)}
.accent-swatch[data-accent-value="holo-orange"]{background-image:linear-gradient(100deg,#D22C00,#FF5E10,#FBA96F,#FF8610,#E68C00,#D22C00,#FF5E10,#FBA96F,#FF8610,#E68C00)}
.accent-swatch[data-accent-value="holo-red"]{background-image:linear-gradient(100deg,#EF0735,#FE3546,#F69999,#FE4635,#F84012,#EF0735,#FE3546,#F69999,#FE4635,#F84012)}
.accent-swatch[data-accent-value="holo-green"]{background-image:linear-gradient(100deg,#119927,#11D649,#5FE390,#11D66A,#12AC6A,#119927,#11D649,#5FE390,#11D66A,#12AC6A)}
.accent-swatch[data-accent-value="holo-blue"]{background-image:linear-gradient(100deg,#008DF4,#3291FF,#93BAFA,#326FFF,#0935FF,#008DF4,#3291FF,#93BAFA,#326FFF,#0935FF)}

/* Карточки выбора темы — мини-превью (тёмный/светлый/чёрный квадратик) вместо голого
   текста, чтобы пользователь визуально понимал разницу до клика, не только по названию. */
.theme-options{display:flex;flex-direction:column;gap:10px}
.theme-option{
  display:flex;align-items:center;gap:14px;
  padding:12px 14px;border-radius:12px;
  background:var(--bg-card-alt);border:1px solid var(--border);
  cursor:pointer;transition:.2s;
}
.theme-option:hover{border-color:var(--accent)}
.theme-option.active{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent)}
.theme-preview{
  width:38px;height:38px;border-radius:10px;flex-shrink:0;
  border:1px solid rgba(255,255,255,.08);
}
.theme-preview.preview-dark{background:linear-gradient(135deg,#1A1D24,#0F1115)}
.theme-preview.preview-light{background:linear-gradient(135deg,#FFFFFF,#E5E7EB)}
.theme-preview.preview-oled{background:linear-gradient(135deg,#0A0A0A,#000000)}
.theme-option-text b{font-size:14px;display:block}
.theme-option-text span{font-size:12px;color:var(--text-secondary)}

/* Переключатель языка внутри панели — тот же .lang-switch стиль что и раньше, теперь
   просто живёт в новом месте, плюс версия сайта под ним как обычная строка метаданных. */
.settings-lang-row{
  display:flex;align-items:center;justify-content:space-between;
  padding:12px 14px;border-radius:12px;
  background:var(--bg-card-alt);border:1px solid var(--border);
}
.settings-lang-row span{font-size:14px;color:var(--text-secondary)}
.lang-switch{
  background:var(--bg-card);border:1px solid var(--border);color:var(--text-primary);
  padding:8px 14px;border-radius:9px;font-size:13px;font-weight:600;
  cursor:pointer;transition:.2s;
}
.lang-switch:hover{border-color:var(--accent)}
.settings-version-row{
  font-size:13px;color:var(--text-muted);
  display:flex;align-items:center;justify-content:space-between;
  padding-top:4px;
}
/* Пульсирующая точка-статус рядом с версией сайта — дешёвая, но узнаваемая деталь
   в духе "онлайн"-индикаторов Discord/Slack. Чисто декоративная (сайт статичный,
   не проверяет реальный статус сервера), сигнализирует "всё работает" на уровне
   ощущения, не факта — если в будущем появится реальная проверка статуса (аптайм
   API и т.п.), эту же точку можно запитать от неё без изменения разметки. */
.status-dot{
  width:8px;height:8px;border-radius:50%;
  background:var(--success);
  flex-shrink:0;
  position:relative;
}
.status-dot::after{
  content:'';
  position:absolute;inset:0;
  border-radius:50%;
  background:var(--success);
  animation:statusPulse 2s ease-out infinite;
}
@keyframes statusPulse{
  0%{transform:scale(1);opacity:.7}
  100%{transform:scale(2.4);opacity:0}
}
