/* ===== ТЕМЫ (CSS-переменные) ===== */
:root,[data-theme="dark"]{--ink-rgb:12 15 20;--surf-rgb:20 26 34;--surf2-rgb:28 36 47;--line-rgb:39 49 62;--mark-rgb:245 197 24;--cool-rgb:91 141 239;--ok-rgb:61 214 140;--bad-rgb:244 98 110;--txt-rgb:243 244 246;--ink:rgb(var(--ink-rgb));--surf:rgb(var(--surf-rgb));--surf2:rgb(var(--surf2-rgb));--line:rgb(var(--line-rgb));--mark:rgb(var(--mark-rgb));--cool:rgb(var(--cool-rgb));--ok:rgb(var(--ok-rgb));--bad:rgb(var(--bad-rgb));--txt:rgb(var(--txt-rgb));--heat0:#283342;--heat1:#5a4a10;--heat2:#a8851a;--heat3:#F5C518;color-scheme:dark}
[data-theme="light"]{--ink-rgb:244 246 251;--surf-rgb:255 255 255;--surf2-rgb:237 241 247;--line-rgb:217 224 236;--mark-rgb:199 127 0;--cool-rgb:47 107 224;--ok-rgb:26 143 85;--bad-rgb:211 45 68;--txt-rgb:22 32 44;--ink:rgb(var(--ink-rgb));--surf:rgb(var(--surf-rgb));--surf2:rgb(var(--surf2-rgb));--line:rgb(var(--line-rgb));--mark:rgb(var(--mark-rgb));--cool:rgb(var(--cool-rgb));--ok:rgb(var(--ok-rgb));--bad:rgb(var(--bad-rgb));--txt:rgb(var(--txt-rgb));--heat0:#DCE3EE;--heat1:#FCE08A;--heat2:#F2B73A;--heat3:#C77F00;color-scheme:light}
/* в светлой теме приглушённые серые Tailwind сливаются с белым фоном — делаем темнее и читаемее */
[data-theme="light"] .text-gray-400{color:#5b6675!important}
[data-theme="light"] .text-gray-500{color:#4a5562!important}
[data-theme="light"] .text-gray-600{color:#3a4452!important}
/* gray-700 используется для «погашенных» значков (неполученные ачивки, пустые
   экраны). В светлой теме он не патчился и рисовался почти чёрным — погашенное
   выглядело заметнее активного. */
[data-theme="light"] .text-gray-700{color:#c3cbd8!important}
[data-theme="light"] .text-gray-100,[data-theme="light"] .text-gray-200,[data-theme="light"] .text-gray-300{color:#16202C!important}
/* --mark #C77F00 как текст на белом даёт 3.25:1 — ниже AA. Фон кнопок не трогаем
   (там ink поверх mark = 5.06:1), затемняем только текстовые варианты. */
[data-theme="light"] .text-mark{color:#9C6200}
[data-theme="light"] .text-ok{color:#137A46}
/* тёмная и catppuccin: тайлвиндовские серые ниже порога AA на этом фоне — поднимаем */
.text-gray-600{color:#8b95a3}
.text-gray-500{color:#9aa4b2}
[data-theme="catppuccin"] .text-gray-400{color:#a6adc8!important}
[data-theme="catppuccin"] .text-gray-500{color:#b0b7d1!important}
[data-theme="catppuccin"] .text-gray-600{color:#a0a6c0!important}
[data-theme="light"] body::before{background:radial-gradient(900px 500px at 80% -10%,rgba(199,127,0,.06),transparent 60%),radial-gradient(700px 500px at -10% 110%,rgba(47,107,224,.05),transparent 60%)}
[data-theme="light"] .card:hover{box-shadow:0 14px 36px -16px rgba(80,90,110,.25)}
[data-theme="light"] .hl{background:linear-gradient(transparent 55%,rgba(199,127,0,.28) 55%)}
[data-theme="catppuccin"]{--ink-rgb:30 30 46;--surf-rgb:24 24 37;--surf2-rgb:49 50 68;--line-rgb:69 71 90;--mark-rgb:249 226 175;--cool-rgb:137 180 250;--ok-rgb:166 227 161;--bad-rgb:243 139 168;--txt-rgb:205 214 244;--ink:rgb(var(--ink-rgb));--surf:rgb(var(--surf-rgb));--surf2:rgb(var(--surf2-rgb));--line:rgb(var(--line-rgb));--mark:rgb(var(--mark-rgb));--cool:rgb(var(--cool-rgb));--ok:rgb(var(--ok-rgb));--bad:rgb(var(--bad-rgb));--txt:rgb(var(--txt-rgb));--heat0:#3a3b50;--heat1:#6c5e4e;--heat2:#c9a96b;--heat3:#f9e2af;color-scheme:dark}
body{font-family:'Manrope',sans-serif;background:var(--ink);color:var(--txt)}
body::before{content:'';position:fixed;inset:0;pointer-events:none;background:radial-gradient(900px 500px at 80% -10%,rgba(245,197,24,.07),transparent 60%),radial-gradient(700px 500px at -10% 110%,rgba(91,141,239,.06),transparent 60%);z-index:0;transform:translateZ(0)}
#app{position:relative;z-index:1}
.hl{background:linear-gradient(transparent 55%,rgba(245,197,24,.45) 55%);padding:0 .15em;border-radius:2px}
svg.lucide{display:inline-block;vertical-align:-0.18em}
/* Вход страницы: короче и полностью на композиторе (translate3d + opacity),
   чтобы кадры не упирались в раскладку. Было .45s + каскад до .59s — почти
   секунда ожидания на каждый переход. */
@keyframes pagein{from{opacity:0;transform:translate3d(0,10px,0)}to{opacity:1;transform:none}}
.pagein{animation:pagein .22s cubic-bezier(.22,.7,.3,1) both}
.stag>*{opacity:0;animation:pagein .26s cubic-bezier(.22,.7,.3,1) forwards}
.stag>*:nth-child(1){animation-delay:.01s}.stag>*:nth-child(2){animation-delay:.035s}.stag>*:nth-child(3){animation-delay:.06s}.stag>*:nth-child(4){animation-delay:.085s}.stag>*:nth-child(5){animation-delay:.11s}.stag>*:nth-child(6){animation-delay:.135s}.stag>*:nth-child(7){animation-delay:.16s}.stag>*:nth-child(8){animation-delay:.175s}.stag>*:nth-child(9){animation-delay:.19s}.stag>*:nth-child(10){animation-delay:.2s}.stag>*:nth-child(11){animation-delay:.21s}.stag>*:nth-child(12){animation-delay:.22s}
/* дальше 12-го каскад не тянем — иначе длинные списки «проявляются» вечность */
.stag>*:nth-child(n+13){animation-delay:.22s}
/* box-shadow в transition заставляет перерисовывать тень каждый кадр:
   держим тень постоянной, а двигаем только transform */
.card{transition:transform .18s cubic-bezier(.22,.7,.3,1),border-color .18s}
.card:hover{transform:translate3d(0,-3px,0);border-color:color-mix(in srgb,var(--line) 65%,var(--txt));box-shadow:0 14px 36px -16px rgba(0,0,0,.7)}
button{transition:transform .12s,background-color .15s,border-color .15s,color .15s}
button:active{transform:scale(.96)}
/* длинные таблицы и списки: браузер не раскладывает то, что за экраном */
.vlist>*{content-visibility:auto;contain-intrinsic-size:auto 56px}
.btn-glow:hover{box-shadow:0 0 28px -4px color-mix(in srgb,var(--mark) 55%,transparent)}
.btn-glow-c:hover{box-shadow:0 0 28px -4px color-mix(in srgb,var(--cool) 50%,transparent)}
@keyframes stripes{to{background-position:28px 0}}
.bar-anim{background-image:linear-gradient(45deg,rgba(255,255,255,.22) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.22) 50%,rgba(255,255,255,.22) 75%,transparent 75%);background-size:28px 28px;animation:stripes .9s linear infinite}
/* Раньше hero бесконечно анимировал background-position: это перерисовка
   всего блока каждый кадр, на слабом железе — постоянные просадки.
   Теперь двигается псевдоэлемент через transform, то есть чистый композитор. */
.hero{position:relative;overflow:hidden;background:linear-gradient(115deg,var(--surf),var(--surf2) 55%,var(--surf))}
.hero::after{content:'';position:absolute;inset:-40% -60%;pointer-events:none;
  background:linear-gradient(115deg,transparent 35%,color-mix(in srgb,var(--mark) 16%,transparent) 50%,transparent 65%);
  animation:heropan 9s linear infinite;will-change:transform}
.hero>*{position:relative;z-index:1}
@keyframes heropan{from{transform:translate3d(-30%,0,0)}to{transform:translate3d(30%,0,0)}}
@keyframes floaty{0%,100%{transform:translateY(0) rotate(-3deg)}50%{transform:translateY(-7px) rotate(3deg)}}
.floaty{animation:floaty 3.6s ease-in-out infinite}
@keyframes popin{from{opacity:0;transform:scale(.6)}to{opacity:1;transform:scale(1)}}
.popin{animation:popin .35s cubic-bezier(.3,1.4,.5,1) both}
.flip-scene{perspective:1200px;cursor:pointer}
.flip-inner{transition:transform .65s cubic-bezier(.4,.1,.2,1);transform-style:preserve-3d;position:relative}
.flip-inner.flipped{transform:rotateY(180deg)}
.flip-face{backface-visibility:hidden;position:absolute;inset:0}
.flip-back{transform:rotateY(180deg)}
@keyframes shake{10%,90%{transform:translateX(-2px)}20%,80%{transform:translateX(4px)}30%,50%,70%{transform:translateX(-6px)}40%,60%{transform:translateX(6px)}}
.shake{animation:shake .45s}
@keyframes pulseok{0%{transform:scale(1)}40%{transform:scale(1.06)}100%{transform:scale(1)}}
.pulseok{animation:pulseok .4s}
@keyframes toastin{from{transform:translateY(20px) scale(.95);opacity:0}to{transform:none;opacity:1}}
.toastin{animation:toastin .35s cubic-bezier(.3,1.2,.5,1)}
@keyframes ringdraw{from{stroke-dashoffset:var(--full)}to{stroke-dashoffset:var(--target)}}
.ringdraw{animation:ringdraw 1.1s cubic-bezier(.3,.7,.3,1) both}
@keyframes spinin{from{transform:rotate(-180deg) scale(.6);opacity:0}to{transform:none;opacity:1}}
.spinin{animation:spinin .4s ease both}
.hm{width:13px;height:13px;border-radius:3px}
.chip{transition:border-color .15s,color .15s,transform .15s}.chip:hover{border-color:var(--mark);color:var(--mark);transform:translateY(-1px)}
.chev{transition:transform .25s}
/* горизонтальные ряды чипов прокручиваются пальцем — полоса только мешает */
.no-sb{scrollbar-width:none;-ms-overflow-style:none}.no-sb::-webkit-scrollbar{display:none}
::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--line) 80%,var(--txt));border-radius:4px}
button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[role="button"]:focus-visible{outline:2px solid var(--mark);outline-offset:2px}
/* Закрытие модалки: подложка и само окно уходят вместе, 150мс. */
@keyframes modalout{to{opacity:0}}
.modal-out{animation:modalout .15s ease-in forwards;pointer-events:none}
.modal-out>[role="dialog"]{transition:transform .15s ease-in;transform:scale(.97)}

/* ===== Выдвижное меню (телефон) ===== */
/* Панель всегда в разметке, наружу уезжает трансформом: открытие идёт
   на композиторе и не пересобирает страницу. 220ms/ease-out — по верхней
   границе «мелкого перехода», дальше движение начинает ощущаться вязким. */
.drawer-panel{transform:translate3d(-100%,0,0);transition:transform .22s cubic-bezier(.22,.7,.3,1)}
#drawer>.absolute.inset-0{opacity:0;transition:opacity .22s ease-out}
#drawer.drawer-open .drawer-panel{transform:none}
#drawer.drawer-open>.absolute.inset-0{opacity:1}

/* Отступ под нижнюю панель — только там, где панель есть. Раньше это был
   инлайновый style на <main>, и он по специфичности перебивал md:pb-8:
   на десктопе под контентом оставалось 96px пустоты. */
.pb-nav{padding-bottom:calc(6rem + env(safe-area-inset-bottom))}
@media(min-width:768px){.pb-nav{padding-bottom:0}
  /* на десктопе нижней панели нет — тосты возвращаются к нижнему краю */
  #toasts{bottom:1.5rem!important}}

/* ===== Телефон ===== */
/* Safari зумит страницу, когда фокус уходит в поле мельче 16px. По всему
   фронту поля подписаны text-sm/text-xs, поэтому поднимаем размер на узких
   экранах разом, а не в сотне мест. */
@media(max-width:767px){
  input,select,textarea{font-size:16px!important}
  /* строка таблицы, свёрнутая в карточку, не должна лепиться к нижней панели */
  .vlist>*{contain-intrinsic-size:auto 120px}
}
/* Плотные админские таблицы на телефоне. Раньше они держали min-w-[660px] /
   min-w-[720px] и на 360px жили в горизонтальной прокрутке: две колонки видно,
   остальные надо искать свайпом. Ниже md таблица раскладывается в карточки —
   каждая ячейка получает подпись из data-label. Разметка одна и та же. */
@media(max-width:767px){
  table.resp,table.resp tbody,table.resp tr,table.resp td{display:block;width:100%}
  table.resp{min-width:0!important}
  table.resp thead{display:none}
  table.resp tr{border:1px solid var(--line);border-radius:14px;margin:0 0 .5rem;padding:.35rem .85rem .55rem;background:var(--surf2)}
  table.resp td{display:flex;align-items:center;justify-content:space-between;gap:.75rem;
    padding:.3rem 0!important;text-align:right;border:0;min-height:32px}
  /* 44px требуется там, где есть во что попадать пальцем — не в каждой строке */
  table.resp td:has(button),table.resp td:has(input),table.resp td:has(select){min-height:44px}
  table.resp td[data-label="Слово"],table.resp td[data-label="Имя"]{font-size:15px;font-weight:700}
  table.resp td+td{border-top:1px solid color-mix(in srgb,var(--line) 60%,transparent)}
  table.resp td::before{content:attr(data-label);flex:0 0 auto;text-align:left;
    font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--txt);opacity:.55}
  table.resp td[data-label='']::before{display:none}
  table.resp td[data-label='']{justify-content:flex-end}
  table.resp td>div,table.resp td>button,table.resp td>select{margin-left:auto}
}
/* Мелкие иконочные кнопки (дерево категорий, действия в строках) пальцем
   не берутся: 14x14px при рекомендованных 44x44. На тач-устройствах
   расширяем область нажатия, не раздвигая саму раскладку. */
@media(pointer:coarse){
  .tapbig{position:relative}
  .tapbig::after{content:'';position:absolute;top:50%;left:50%;width:44px;height:44px;transform:translate(-50%,-50%)}
}
@media(prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}.stag>*{opacity:1!important}}
/* Скелетон: мягкая пульсация прозрачности вместо «бегущего блика» —
   одно свойство на композиторе, без перерисовки градиента каждый кадр. */
.sk{background:var(--surf2);animation:skpulse 1.4s ease-in-out infinite}
@keyframes skpulse{0%,100%{opacity:.45}50%{opacity:.8}}
.spinner{width:40px;height:40px;border:3px solid var(--surf2);border-top-color:var(--mark);border-radius:50%;animation:spin .8s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
