/* ==========================================================================
   XANYMAN Fitness — дизайн-система.
   Стекло здесь не «blur поверх градиента», а материал: зерно, спекулярная
   кромка, три уровня глубины и блик, идущий за курсором. Структура и метрики
   (сайдбар 290/90, 12 колонок, шкалы токенов) — по TailAdmin; всё остальное
   своё. Собрано без сборщика: хостингу не нужен node.
   ========================================================================== */

/* ── шрифты (локальные, без CDN — CSP остаётся закрытым) ─────────────────── */
@font-face{font-family:Montserrat;font-style:normal;font-weight:400 900;font-display:swap;
  src:url(../fonts/montserrat-cyrillic.woff2) format('woff2');
  unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;}
@font-face{font-family:Montserrat;font-style:normal;font-weight:400 900;font-display:swap;
  src:url(../fonts/montserrat-latin.woff2) format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
    U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;}
@font-face{font-family:Manrope;font-style:normal;font-weight:400 700;font-display:swap;
  src:url(../fonts/manrope-cyrillic.woff2) format('woff2');
  unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;}
@font-face{font-family:Manrope;font-style:normal;font-weight:400 700;font-display:swap;
  src:url(../fonts/manrope-latin.woff2) format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
    U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;}

/* ══════════════════════ ТОКЕНЫ ══════════════════════ */
:root{
  /* Сигнатурный цвет — кислотный лайм. Он несёт всю энергию, поэтому
     остальная палитра нарочно приглушена до графита с тёплым подмесом. */
  --lime-300:#E4FF8F; --lime-400:#D6FF63; --lime-500:#C8F542; --lime-600:#A8D31F;
  --lime-700:#7E9E13; --lime-glow:rgba(200,245,66,.28);

  --ember-400:#FF8A6B; --ember-500:#FF6B4A; --ember-600:#E8452  0;
  --ember:#FF6B4A;

  /* нейтрали с тёплым подмесом — холодные серые выдают шаблон */
  --n-0:#FFFFFF;  --n-25:#FAFAF7; --n-50:#F4F4EF; --n-100:#E9E9E1;
  --n-200:#D7D7CC; --n-300:#B8B8AB; --n-400:#8E8E83; --n-500:#6B6B62;
  --n-600:#4D4D46; --n-700:#33332E; --n-800:#1F1F1C; --n-900:#131311;
  --ink:#07090C; --ink-2:#0C1015; --ink-3:#12171E;

  --ok:#4ADE80; --ok-dim:rgba(74,222,128,.14);
  --warn:#FBBF24; --warn-dim:rgba(251,191,36,.14);
  --bad:#FB7185; --bad-dim:rgba(251,113,133,.14);

  /* типографика */
  --font-display:Montserrat,'Segoe UI',system-ui,sans-serif;
  --font-ui:Montserrat,'Segoe UI',system-ui,sans-serif;
  --font-text:Manrope,Montserrat,system-ui,sans-serif;
  --font-mono:ui-monospace,'SF Mono',SFMono-Regular,Menlo,monospace;

  --t-display:clamp(2.75rem,7vw,5.5rem);
  --t-h1:clamp(1.875rem,3.4vw,3rem);
  --t-h2:clamp(1.375rem,2.2vw,1.875rem);
  --t-h3:1.0625rem;
  --t-lg:1.0625rem; --t-md:.9375rem; --t-sm:.8125rem; --t-xs:.6875rem;

  --tracking-display:-.045em; --tracking-h:-.025em; --tracking-eyebrow:.18em;

  /* метрики TailAdmin */
  --sidebar-w:290px; --sidebar-w-min:90px;
  --r-xl:1.5rem; --r-lg:1.125rem; --r-md:.75rem; --r-sm:.5rem; --r-pill:999px;

  --ease:cubic-bezier(.22,1,.36,1);
  --ease-out:cubic-bezier(.16,1,.3,1);
  --dur:.45s;

  /* ── стекло: тёмная тема (основная) ── */
  --bg:var(--ink);
  --fg:rgba(255,255,255,.80);
  --fg-dim:rgba(255,255,255,.46);
  --fg-max:#fff;
  --accent:var(--lime-400);
  --accent-ink:#0A0C08;

  --g1-bg:linear-gradient(180deg,rgba(255,255,255,.085),rgba(255,255,255,.018) 45%,
          rgba(255,255,255,.05)),rgba(9,12,17,.46);          /* карточка */
  --g2-bg:linear-gradient(180deg,rgba(255,255,255,.10),rgba(255,255,255,.035)),
          rgba(9,12,17,.58);                                  /* шасси */
  --g3-bg:linear-gradient(180deg,rgba(255,255,255,.12),rgba(255,255,255,.05)),
          rgba(9,12,17,.34);                                  /* поля, чипы */
  --g-edge:rgba(255,255,255,.10);
  --g-edge-hi:rgba(255,255,255,.34);
  --g-hair:rgba(255,255,255,.075);
  --g-blur:26px;
  --g-shadow:0 1px 1px rgba(0,0,0,.28),0 12px 32px -12px rgba(0,0,0,.7);
  --g-shadow-hi:0 1px 1px rgba(0,0,0,.3),0 28px 60px -20px rgba(0,0,0,.85);
  --spec:rgba(255,255,255,.09);     /* блик за курсором */
  --art-filter:invert(1) hue-rotate(180deg) saturate(1.2) brightness(1.04);
  --cover-fade:rgba(7,9,12,.72);
  --scrim:rgba(7,9,12,.72);
}

/* ── светлая тема: бумага, не бело-синий больничный ── */
:root.light{
  --bg:#EFEFE8;
  --fg:rgba(19,19,17,.78);
  --fg-dim:rgba(19,19,17,.48);
  --fg-max:#0B0C0A;
  --accent:var(--lime-600);
  --accent-ink:#0A0C08;

  --g1-bg:linear-gradient(180deg,rgba(255,255,255,.80),rgba(255,255,255,.52)),
          rgba(255,255,255,.3);
  --g2-bg:linear-gradient(180deg,rgba(255,255,255,.88),rgba(255,255,255,.66)),
          rgba(255,255,255,.4);
  --g3-bg:linear-gradient(180deg,rgba(255,255,255,.92),rgba(255,255,255,.74)),
          rgba(255,255,255,.5);
  --g-edge:rgba(255,255,255,.85);
  --g-edge-hi:rgba(255,255,255,1);
  --g-hair:rgba(19,19,17,.09);
  --g-shadow:0 1px 1px rgba(19,19,17,.04),0 14px 34px -14px rgba(19,19,17,.22);
  --g-shadow-hi:0 1px 1px rgba(19,19,17,.05),0 30px 60px -22px rgba(19,19,17,.3);
  --spec:rgba(255,255,255,.75);
  --art-filter:none;
  --cover-fade:rgba(255,255,255,.66);
  --scrim:rgba(239,239,232,.75);
}

/* ══════════════════════ БАЗА ══════════════════════ */
*,*::before,*::after{box-sizing:border-box;}
/* clip, а не hidden: hidden на одной оси заставляет браузер сделать вторую
   прокручиваемой и превращает корень в контейнер прокрутки, из-за чего
   position:sticky и якоря ведут себя иначе. clip только обрезает. Держать
   его надо именно на html: overflow у body доезжает до вьюпорта не всегда,
   и на телефоне страница ходила вбок, хотя ни один блок не шире экрана. */
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;
  overflow-x:clip;overscroll-behavior-x:none;}
body{
  margin:0;min-height:100svh;background:var(--bg);color:var(--fg);
  font-family:var(--font-ui);font-size:var(--t-md);line-height:1.6;
  font-weight:450;letter-spacing:-.005em;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  overflow-x:clip;
}

/* ── Атмосфера. Не три радиальных пятна, а мягкие цветовые поля разного
      масштаба, которые медленно дышат: только тогда блюр имеет что размывать. ── */
.atmo{position:fixed;inset:0;z-index:-3;pointer-events:none;overflow:hidden;}
.atmo::after{content:'';position:absolute;inset:0;
  background:radial-gradient(135% 105% at 50% 12%,transparent 26%,var(--bg) 96%);}
.atmo i{position:absolute;display:block;border-radius:50%;filter:blur(64px);opacity:.9;}
.atmo i:nth-child(1){width:52vw;height:52vw;left:-12vw;top:-16vw;
  background:radial-gradient(circle,rgba(200,245,66,.62),transparent 68%);
  animation:drift1 34s var(--ease) infinite alternate;}
.atmo i:nth-child(2){width:38vw;height:38vw;right:-8vw;top:-6vh;
  background:radial-gradient(circle,rgba(255,107,74,.36),transparent 66%);
  animation:drift2 41s var(--ease) infinite alternate;}
.atmo i:nth-child(3){width:60vw;height:60vw;left:22vw;bottom:-28vw;
  background:radial-gradient(circle,rgba(92,120,255,.52),transparent 68%);
  animation:drift3 48s var(--ease) infinite alternate;}
.atmo i:nth-child(4){width:30vw;height:30vw;right:18vw;bottom:8vh;
  background:radial-gradient(circle,rgba(200,245,66,.34),transparent 64%);
  animation:drift2 37s var(--ease) infinite alternate-reverse;}
:root.light .atmo i{opacity:.55;filter:blur(70px);}
@keyframes drift1{to{transform:translate3d(6vw,8vh,0) scale(1.14);}}
@keyframes drift2{to{transform:translate3d(-7vw,6vh,0) scale(1.18);}}
@keyframes drift3{to{transform:translate3d(5vw,-7vh,0) scale(1.1);}}

/* ── Зерно. Один слой плёнки убирает «пластик» вернее любых теней. ── */
.grain{position:fixed;inset:0;z-index:-2;pointer-events:none;overflow:hidden;
  opacity:.5;mix-blend-mode:overlay;}
.grain::after{content:'';position:absolute;inset:-12%;
  background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E");
  animation:grainshift 6s steps(6) infinite;}
:root.light .grain{opacity:.32;mix-blend-mode:multiply;}
@keyframes grainshift{
  0%{transform:translate(0,0)}20%{transform:translate(-3%,2%)}40%{transform:translate(2%,-3%)}
  60%{transform:translate(-2%,-2%)}80%{transform:translate(3%,1%)}100%{transform:translate(0,0)}}

/* ── Сетка-подложка: даёт стеклу структуру, которую видно сквозь блюр. ── */
.mesh{position:fixed;inset:0;z-index:-1;pointer-events:none;opacity:.5;
  background-image:linear-gradient(var(--g-hair) 1px,transparent 1px),
                   linear-gradient(90deg,var(--g-hair) 1px,transparent 1px);
  background-size:88px 88px;
  -webkit-mask-image:radial-gradient(120% 90% at 50% 0%,#000 8%,transparent 72%);
  mask-image:radial-gradient(120% 90% at 50% 0%,#000 8%,transparent 72%);}

/* ══════════════════════ ТИПОГРАФИКА ══════════════════════ */
h1,h2,h3,h4{margin:0;font-family:var(--font-display);color:var(--fg-max);
  font-weight:800;letter-spacing:var(--tracking-h);line-height:1.12;text-wrap:balance;}
h1{font-size:var(--t-h1);} h2{font-size:var(--t-h2);} h3{font-size:var(--t-h3);font-weight:700;}
p{margin:0 0 .85rem;}
.prose{font-family:var(--font-text);font-weight:400;line-height:1.7;letter-spacing:0;}
.display{font-family:var(--font-display);font-size:var(--t-display);font-weight:900;
  letter-spacing:var(--tracking-display);line-height:.92;color:var(--fg-max);text-wrap:balance;}
.display em{font-style:normal;color:var(--accent);}
/* Надзаголовок в разрядку — ходовой приём редакторской вёрстки, дёшево и точно. */
.eyebrow{display:inline-flex;align-items:center;gap:.55rem;
  font-size:var(--t-xs);font-weight:700;text-transform:uppercase;
  letter-spacing:var(--tracking-eyebrow);color:var(--fg-dim);}
.eyebrow::before{content:'';width:1.5rem;height:1px;background:currentColor;opacity:.6;}
.eyebrow.no-rule::before{display:none;}
.num{font-family:var(--font-display);font-weight:800;letter-spacing:-.04em;
  font-variant-numeric:tabular-nums;color:var(--fg-max);line-height:1;}
.mono{font-family:var(--font-mono);font-variant-ligatures:none;}
.muted{color:var(--fg-dim);} .strong{color:var(--fg-max);font-weight:700;}
.sm{font-size:var(--t-sm);} .xs{font-size:var(--t-xs);} .lg{font-size:var(--t-lg);}
.nowrap{white-space:nowrap;} .center{text-align:center;}
a{color:inherit;text-decoration:none;}
.link{display:inline-flex;align-items:center;gap:.375rem;color:var(--accent);text-underline-offset:.22em;
  text-decoration:underline;text-decoration-thickness:1px;
  text-decoration-color:color-mix(in srgb,var(--accent) 40%,transparent);}
.link:hover{text-decoration-color:var(--accent);}
::selection{background:var(--accent);color:var(--accent-ink);}
img,video{display:block;max-width:100%;}
/* Инлайновая иконка по умолчанию равна строке. Без этого SVG без width
   растягивается на всю ширину родителя и разносит вёрстку. */
svg{display:block;width:1.15em;height:1.15em;flex:none;}
button,input,select,textarea{font:inherit;color:inherit;}
hr{border:0;border-top:1px solid var(--g-hair);margin:1.35rem 0;}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;}

/* Шапка липкая и перекрывает первые строки, поэтому ссылка не уезжает за
   край, а выезжает поверх неё: иначе с клавиатуры первым делом приходилось
   прощёлкивать логотип, навигацию, языки, тему и выход — пять остановок до
   контента на каждой странице. Видна только в фокусе, мышью её не поймать. */
.skip{position:fixed;top:.75rem;left:.75rem;z-index:60;
  transform:translateY(calc(-100% - 1.5rem));
  padding:.625rem 1rem;border-radius:var(--r-md);
  background:var(--accent);color:var(--accent-ink);
  font-weight:600;font-size:var(--t-sm);text-decoration:none;
  box-shadow:0 .5rem 1.5rem rgba(0,0,0,.45);
  transition:transform .18s var(--ease);}
.skip:focus-visible{transform:none;}
@media(prefers-reduced-motion:reduce){.skip{transition:none;}}
/* Цель пропуска фокусируется программно — рамку вокруг всей страницы не рисуем.
   Отступ прокрутки на высоту липкой шапки: без него прыжок ставил первую
   строку ровно под шапку, и человек попадал на скрытый текст. */
#main{scroll-margin-top:5rem;}
#main:focus{outline:none;}

/* ══════════════════════ РАСКЛАДКА ══════════════════════ */
/* padding-inline через max(): при viewport-fit=cover в альбомной ориентации
   контент уезжает под вырез, а env() без выреза равен нулю — то есть на
   обычном экране поля остаются ровно те же 1.25rem. */
.wrap{width:100%;max-width:1400px;margin-inline:auto;
  padding-inline:max(1.25rem,env(safe-area-inset-left))
                 max(1.25rem,env(safe-area-inset-right));}
@media(min-width:768px){.wrap{padding-inline:2rem;}}
@media(min-width:1280px){.wrap{padding-inline:2.5rem;}}
.narrow{max-width:940px;}
.grid{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:1rem;}
@media(min-width:768px){.grid{gap:1.5rem;}}
[class*=c-]{grid-column:span 12;}
@media(min-width:640px){.c-3,.c-4,.c-6{grid-column:span 6;}}
@media(min-width:1024px){
  .c-2{grid-column:span 2;}.c-3{grid-column:span 3;}.c-4{grid-column:span 4;}
  .c-5{grid-column:span 5;}.c-6{grid-column:span 6;}.c-7{grid-column:span 7;}
  .c-8{grid-column:span 8;}.c-9{grid-column:span 9;}}
.row{display:flex;align-items:center;gap:.75rem;}
.row-between{display:flex;align-items:center;justify-content:space-between;gap:1.25rem;flex-wrap:wrap;}
.col{display:flex;flex-direction:column;gap:1rem;}
.grow{flex:1 1 auto;min-width:0;}
.flexwrap{display:flex;flex-wrap:wrap;gap:.5rem;}
.mt-1{margin-top:.5rem}.mt-2{margin-top:1rem}.mt-3{margin-top:1.5rem}.mt-4{margin-top:2.5rem}
.mb-0{margin-bottom:0}.mb-1{margin-bottom:.5rem}.mb-2{margin-bottom:1rem}
.mb-3{margin-bottom:1.5rem}.mb-4{margin-bottom:2.5rem}
.hide{display:none!important;}

/* ══════════════════════ СТЕКЛО ══════════════════════
   Четыре слоя на одном элементе:
   1) полупрозрачная заливка + backdrop-filter — сам материал;
   2) ::before — спекулярная кромка: градиентный бордюр через mask-composite,
      яркий сверху-слева и растворяющийся книзу (ровный 1px border — главный
      признак шаблона);
   3) ::after — блик, который идёт за курсором (--mx/--my ставит JS);
   4) .grain поверх всей страницы.                                            */
.glass{position:relative;border-radius:var(--r-lg);background:var(--g1-bg);
  backdrop-filter:blur(var(--g-blur)) saturate(1.7);
  -webkit-backdrop-filter:blur(var(--g-blur)) saturate(1.7);
  box-shadow:var(--g-shadow);isolation:isolate;}
.glass::before{content:'';position:absolute;inset:0;border-radius:inherit;padding:1px;
  background:linear-gradient(145deg,var(--g-edge-hi),var(--g-edge) 28%,
             transparent 55%,var(--g-edge) 100%);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;mask-composite:exclude;pointer-events:none;z-index:2;}
.glass::after{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  opacity:0;transition:opacity .4s var(--ease);z-index:1;
  background:radial-gradient(320px circle at var(--mx,50%) var(--my,0%),
             var(--spec),transparent 70%);}
.glass:hover::after{opacity:1;}
.glass-2{background:var(--g2-bg);}
.glass-3{background:var(--g3-bg);}
.glass-xl{border-radius:var(--r-xl);}
/* Без backdrop-filter стекло превращается в плотную панель, а не в мутную кашу. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .glass{background:var(--ink-2);}
  :root.light .glass{background:rgba(255,255,255,.94);}
}
.lift{transition:transform .5s var(--ease),box-shadow .5s var(--ease);}
.lift:hover{transform:translateY(-4px);box-shadow:var(--g-shadow-hi);}
.pad{padding:1.5rem;}
@media(min-width:768px){.pad{padding:1.875rem;}}
.pad-sm{padding:1.125rem 1.25rem;}
.head{display:flex;align-items:center;justify-content:space-between;gap:1rem;
  padding:1.125rem 1.5rem;border-bottom:1px solid var(--g-hair);}
.head h3{font-size:var(--t-md);letter-spacing:-.015em;}

/* ══════════════════════ КНОПКИ ══════════════════════ */
.btn{--btn-bg:var(--g3-bg);--btn-fg:var(--fg-max);
  position:relative;display:inline-flex;align-items:center;justify-content:center;gap:.5rem;
  padding:.75rem 1.375rem;border:0;border-radius:var(--r-pill);cursor:pointer;
  font-family:var(--font-ui);font-size:var(--t-sm);font-weight:700;letter-spacing:-.01em;
  background:var(--btn-bg);color:var(--btn-fg);white-space:nowrap;overflow:hidden;
  transition:transform .3s var(--ease),box-shadow .3s var(--ease),
             background .3s var(--ease),color .3s var(--ease);}
.btn::before{content:'';position:absolute;inset:0;border-radius:inherit;padding:1px;
  background:linear-gradient(150deg,var(--g-edge-hi),transparent 60%);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;mask-composite:exclude;opacity:.8;}
.btn:hover{transform:translateY(-2px);}
.btn:active{transform:translateY(0);}
.btn:focus-visible{outline:2px solid var(--accent);outline-offset:3px;}
.btn-primary{--btn-bg:var(--accent);--btn-fg:var(--accent-ink);
  box-shadow:0 6px 22px -8px var(--lime-glow);}
.btn-primary:hover{box-shadow:0 12px 32px -8px var(--lime-glow);}
.btn-solid{--btn-bg:var(--fg-max);--btn-fg:var(--bg);}
.btn-ghost{--btn-bg:transparent;box-shadow:inset 0 0 0 1px var(--g-edge);}
.btn-ghost:hover{--btn-bg:var(--g3-bg);}
.btn-danger{--btn-bg:var(--bad-dim);--btn-fg:var(--bad);}
.btn-sm{padding:.4375rem .875rem;font-size:var(--t-xs);}
.btn-lg{padding:1rem 2rem;font-size:var(--t-md);}
.btn-block{width:100%;}
.btn-icon{padding:0;width:2.5rem;height:2.5rem;}
.btn svg{width:1.05em;height:1.05em;stroke-width:2.2;}
/* Стрелка, выезжающая на ховере — маленькая деталь, которая читается как «сделано руками». */
.btn .arr{transition:transform .35s var(--ease);}
.btn:hover .arr{transform:translateX(3px);}

/* ══════════════════════ ФОРМЫ ══════════════════════ */
.field{display:block;margin-bottom:1.125rem;}
.label{display:block;margin-bottom:.4375rem;font-size:var(--t-xs);font-weight:700;
  text-transform:uppercase;letter-spacing:.1em;color:var(--fg-dim);}
.input,.select,.textarea{width:100%;padding:.8125rem 1rem;border-radius:var(--r-md);
  background:var(--g3-bg);border:1px solid var(--g-edge);color:var(--fg-max);
  font-family:var(--font-ui);font-size:var(--t-md);font-weight:500;
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  transition:border-color .3s var(--ease),box-shadow .3s var(--ease),background .3s var(--ease);}
.input::placeholder,.textarea::placeholder{color:var(--fg-dim);font-weight:400;}
.input:focus,.select:focus,.textarea:focus{outline:0;border-color:var(--accent);
  box-shadow:0 0 0 4px color-mix(in srgb,var(--accent) 16%,transparent);}
.field.bad .input{border-color:var(--bad);}
.field.bad .hint{color:var(--bad);}
.hint{margin-top:.4375rem;font-size:var(--t-xs);color:var(--fg-dim);}

/* Галочка в форме: своего чекбокса в проекте не было, а правило доступа —
   не то место, где уместен системный синий квадратик на стекле. */
.field-check{display:flex;align-items:flex-start;gap:.75rem;cursor:pointer;}
.field-check input[type=checkbox]{flex:0 0 auto;appearance:none;-webkit-appearance:none;
  width:1.125rem;height:1.125rem;margin:.0625rem 0 0;border-radius:var(--r-sm);
  border:1px solid var(--n-0);background:rgba(255,255,255,.04);cursor:pointer;
  transition:background .16s var(--ease),border-color .16s var(--ease);}
.field-check input[type=checkbox]:checked{background:var(--accent);border-color:var(--accent);}
/* Галка рисуется рамкой повёрнутого прямоугольника — без картинки и без CSP. */
.field-check input[type=checkbox]:checked::after{content:'';display:block;
  width:.3125rem;height:.5625rem;margin:.0625rem auto 0;
  border:solid var(--ink);border-width:0 2px 2px 0;transform:rotate(45deg);}
.field-check input[type=checkbox]:focus-visible{outline:2px solid var(--accent);outline-offset:2px;}
.field-check .label{margin-bottom:.1875rem;}
.field-check .hint{margin-top:0;}
.textarea{min-height:7.5rem;resize:vertical;font-family:var(--font-text);}
.select{appearance:none;padding-right:2.5rem;cursor:pointer;
  background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='none' stroke='%238E8E83' stroke-width='2.2' stroke-linecap='round'%3E%3Cpath d='M3 5.5L7 9.5l4-4'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 1rem center;}
.check{display:inline-flex;align-items:center;gap:.5rem;cursor:pointer;font-size:var(--t-sm);}
.check input{width:1.0625rem;height:1.0625rem;accent-color:var(--accent);}

/* Поле ввода кода: крупный моноширинный, разрядка под группы по 4 символа. */
.code-field{position:relative;}
.code-input{width:100%;padding:1.375rem 1rem;border-radius:var(--r-md);
  background:var(--g3-bg);border:1px solid var(--g-edge);color:var(--fg-max);
  font-family:var(--font-mono);font-size:clamp(1.0625rem,3.6vw,1.375rem);font-weight:600;
  letter-spacing:.22em;text-align:center;text-transform:uppercase;
  transition:border-color .3s var(--ease),box-shadow .3s var(--ease);}
.code-input::placeholder{letter-spacing:.22em;color:var(--fg-dim);}
.code-input:focus{outline:0;border-color:var(--accent);
  box-shadow:0 0 0 4px color-mix(in srgb,var(--accent) 16%,transparent),
             0 0 40px -12px var(--lime-glow);}
.code-out{font-family:var(--font-mono);font-size:clamp(1rem,3.4vw,1.3125rem);font-weight:700;
  letter-spacing:.16em;text-align:center;color:var(--accent);
  padding:1rem;border-radius:var(--r-md);
  background:color-mix(in srgb,var(--accent) 8%,transparent);
  border:1px dashed color-mix(in srgb,var(--accent) 45%,transparent);}

/* ══════════════════════ БЕЙДЖИ, ПЛАШКИ ══════════════════════ */
.badge{display:inline-flex;align-items:center;gap:.375rem;padding:.3125rem .6875rem;
  border-radius:var(--r-pill);font-size:var(--t-xs);font-weight:700;
  letter-spacing:.02em;line-height:1.35;white-space:nowrap;}
.badge-accent{background:color-mix(in srgb,var(--accent) 16%,transparent);color:var(--accent);}
.badge-ok{background:var(--ok-dim);color:var(--ok);}
.badge-warn{background:var(--warn-dim);color:var(--warn);}
.badge-bad{background:var(--bad-dim);color:var(--bad);}
.badge-mute{background:var(--g3-bg);color:var(--fg-dim);}
:root.light .badge-ok{color:#15803D;} :root.light .badge-warn{color:#A16207;}
:root.light .badge-bad{color:#BE123C;} :root.light .badge-accent{color:var(--lime-700);}
.dot{width:.4375rem;height:.4375rem;border-radius:50%;background:currentColor;flex:none;}
.dot-live{animation:live 2.4s var(--ease) infinite;}
@keyframes live{0%,100%{box-shadow:0 0 0 0 currentColor;opacity:1;}
  50%{box-shadow:0 0 0 .3125rem transparent;opacity:.65;}}

.alert{display:flex;gap:.875rem;padding:1rem 1.125rem;border-radius:var(--r-md);
  font-size:var(--t-sm);line-height:1.55;border:1px solid transparent;}
.alert svg{flex:none;width:1.125rem;height:1.125rem;margin-top:.125rem;}
.alert-ok{background:var(--ok-dim);border-color:color-mix(in srgb,var(--ok) 28%,transparent);color:var(--ok);}
.alert-warn{background:var(--warn-dim);border-color:color-mix(in srgb,var(--warn) 28%,transparent);color:var(--warn);}
.alert-bad{background:var(--bad-dim);border-color:color-mix(in srgb,var(--bad) 28%,transparent);color:var(--bad);}
.alert-info{background:var(--g3-bg);border-color:var(--g-edge);color:var(--fg);}
:root.light .alert-ok{color:#15803D;} :root.light .alert-warn{color:#A16207;}
:root.light .alert-bad{color:#BE123C;}

.chip{display:inline-flex;align-items:center;gap:.375rem;padding:.4375rem .875rem;
  border-radius:var(--r-pill);font-size:var(--t-sm);font-weight:600;cursor:pointer;
  background:var(--g3-bg);color:var(--fg);border:1px solid var(--g-edge);
  /* перечислено поимённо, а не all: с all в переход попадали и размеры,
     и на смене фильтра чипы дёргались шириной */
  transition:color .28s var(--ease),background .28s var(--ease),
             border-color .28s var(--ease),transform .18s var(--ease);}
.chip:hover{border-color:color-mix(in srgb,var(--accent) 50%,transparent);color:var(--fg-max);}
.chip:active{transform:scale(.97);}
.chip.on{background:var(--accent);border-color:var(--accent);color:var(--accent-ink);}
.chip .n{opacity:.55;font-weight:500;font-size:var(--t-xs);}

/* ── фильтр по зонам тела ──
   Плитки, а не чипсы в строку. Сетка из шести долей: обычная плитка берёт
   две — три в ряд; хвост (11 зон = 3+3+3+2) берёт по три, и последний ряд
   выходит полным, а не с одинокой кнопкой у левого края. Подписи на
   одиннадцати языках разной длины, поэтому текст живёт под фигурой:
   ширина плитки тогда от длины слова не зависит вовсе. */
.zones{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));
  gap:.625rem;max-width:46rem;margin-inline:auto;}
.zones>.zone-t{grid-column:span 2;}
.zones-r2>.zone-t:nth-last-child(-n+2){grid-column:span 3;}
.zones-r1>.zone-t:last-child{grid-column:3 / span 2;}

.zone-t{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:.375rem;padding:.875rem .5rem .75rem;text-align:center;
  border-radius:var(--r-md);background:var(--g3-bg);border:1px solid var(--g-edge);
  color:var(--fg);text-decoration:none;
  /* поимённо, а не all: с all в переход попадали размеры, и на смене
     фильтра плитки дёргались шириной */
  transition:color .28s var(--ease),background .28s var(--ease),
             border-color .28s var(--ease),transform .18s var(--ease);}
.zone-t:hover{border-color:color-mix(in srgb,var(--accent) 50%,transparent);
  color:var(--fg-max);}
.zone-t:active{transform:scale(.975);}
.zone-t.on{background:var(--accent);border-color:var(--accent);color:var(--accent-ink);}
.zone-t-n{font-size:var(--t-sm);font-weight:600;line-height:1.2;
  overflow-wrap:anywhere;hyphens:auto;}
.zone-t-c{font-size:var(--t-xs);font-weight:500;opacity:.55;line-height:1;}
.zone-t-i{display:block;}

.i-zone{width:1.125rem;height:1.125rem;flex:none;}
.i-zone-lg{display:block;width:2.75rem;height:2.75rem;
  transition:transform .28s var(--ease);}
.zone-t:hover .i-zone-lg{transform:scale(1.07);}

@media(max-width:560px){
  .zones{gap:.5rem;}
  .zone-t{padding:.75rem .375rem .625rem;gap:.25rem;}
  .i-zone-lg{width:2.25rem;height:2.25rem;}
  .zone-t-n{font-size:var(--t-xs);}
}
@media(prefers-reduced-motion:reduce){
  .zone-t,.i-zone-lg{transition:none;}
  .zone-t:hover .i-zone-lg,.zone-t:active{transform:none;}
}

/* ══════════════════════ ИЛЛЮСТРАЦИИ УПРАЖНЕНИЙ ══════════════════════
   Белый фон вырезан на этапе сборки (tools/cutout.py), в файле уже альфа.
   Смешивание тут не работает в принципе: .glass изолирован (isolation:isolate),
   и screen смешался бы не с атмосферой за карточкой, а с её же тёмной заливкой —
   отсюда были чёрные плитки. Тему делает только фильтр:
   тёмная — invert белит штрих, hue-rotate возвращает красной подсветке тепло;
   светлая — оригинальные цвета как есть.                                       */
.art{filter:var(--art-filter);}
.art-box{position:relative;aspect-ratio:1;overflow:hidden;border-radius:var(--r-md);
  display:grid;place-items:center;}
.art-box img{width:100%;height:100%;object-fit:contain;
  filter:var(--art-filter);transition:transform .6s var(--ease);}
.ex:hover .art-box img{transform:scale(1.07);}
.ex .art-box,.lesson .art-box{background:var(--g3-bg);}
/* Крупная иллюстрация — рабочий материал, а не декор: под ней нейтральная
   подложка, иначе цветная атмосфера красит анатомию и мешает читать штрих.    */
/* Кадры теперь собираются в 720 px (scripts/build-assets.py гонит исходные
   180 через Real-ESRGAN), поэтому предел картинки поднят с 14rem до 18rem:
   288 CSS-пикселей — это 576 физических на ретине, файл закрывает с запасом.
   Выше не идём уже не из-за качества, а из-за композиции: фигура во всю плиту
   выглядит как обложка, а не как иллюстрация к тексту.
   Плиту при этом держим за высоту: квадрат по ширине колонки на широком экране
   вырастал в 727 px пустоты вокруг маленького кадра — плита становится полосой,
   кадр остаётся по центру. */
.art-hero{background:
  radial-gradient(120% 100% at 50% 15%,rgba(255,255,255,.06),transparent 68%),
  rgba(8,11,15,.72);}
/* aspect-ratio:1 с .art-box перебивал max-height и давал квадрат 384 px в
   колонке на 787: справа оставалась половина плиты пустой. Ширину отдаём
   колонке, высоту задаём сами — кадр центрируется гридом .art-box. */
.art-hero{aspect-ratio:auto;width:100%;height:min(24rem,52vh);}
/* В светлой теме фильтр анатомии не трогает, и кадр остаётся на своей белой
   подложке из датасета. На тёмной плите он читался как белый квадрат внутри
   серой коробки, поэтому в светлой теме плита тоже белая — граница кадра
   исчезает, остаётся один рисунок. */
:root.light .art-hero{background:
  radial-gradient(120% 100% at 50% 15%,rgba(0,0,0,.05),transparent 68%),#fff;}
/* Исходники теперь 480 px вместо 180, поэтому потолок кадра поднят с 18rem:
   480/336 = 1.43x — рисунок остаётся резким и на обычном экране, а плита
   высотой 24rem вмещает его с воздухом. */
.art-hero img{width:auto;height:auto;
  max-width:min(100%,21rem);max-height:min(100%,21rem);}

/* ══════════════════════ КАРТОЧКИ УПРАЖНЕНИЙ ══════════════════════ */
.ex-grid{display:grid;gap:.875rem;grid-template-columns:repeat(auto-fill,minmax(148px,1fr));}
@media(min-width:768px){.ex-grid{gap:1.25rem;grid-template-columns:repeat(auto-fill,minmax(184px,1fr));}}
.ex{position:relative;border-radius:var(--r-lg);overflow:hidden;padding:.5rem;
  display:flex;flex-direction:column;gap:.5rem;}
.ex-cap{padding:.25rem .5rem .5rem;}
.ex-name{font-size:var(--t-sm);font-weight:700;color:var(--fg-max);line-height:1.3;
  letter-spacing:-.015em;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
.ex-meta{margin-top:.1875rem;font-size:var(--t-xs);color:var(--fg-dim);
  text-transform:lowercase;letter-spacing:.01em;}

/* ══════════════════════ ЗАЩИТА КОНТЕНТА ══════════════════════ */
.protected,.protected *{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none;}
.protected img{-webkit-user-drag:none;pointer-events:none;}
.shield{position:absolute;inset:0;z-index:3;} /* перехватывает «сохранить как» */
.wm{position:absolute;right:.4375rem;bottom:.4375rem;z-index:4;pointer-events:none;
  padding:.125rem .3125rem;border-radius:.25rem;font-family:var(--font-mono);
  font-size:.5625rem;letter-spacing:.1em;color:var(--fg-dim);
  background:color-mix(in srgb,var(--bg) 55%,transparent);}
.wm-page{position:fixed;inset:0;z-index:9998;pointer-events:none;overflow:hidden;
  opacity:.022;display:flex;flex-wrap:wrap;gap:3.5rem;transform:rotate(-22deg) scale(1.5);
  align-content:center;justify-content:center;}
.wm-page span{font-family:var(--font-mono);font-size:1.125rem;letter-spacing:.35em;
  color:var(--fg-max);white-space:nowrap;}
@media print{html{display:none!important;}}

/* ══════════════════════ ТАБЛИЦЫ ══════════════════════ */
.tscroll{overflow-x:auto;}
table.t{width:100%;border-collapse:collapse;font-size:var(--t-sm);}
table.t th{text-align:left;padding:.8125rem 1.5rem;font-size:var(--t-xs);font-weight:700;
  text-transform:uppercase;letter-spacing:.11em;color:var(--fg-dim);
  border-bottom:1px solid var(--g-hair);white-space:nowrap;}
table.t td{padding:1rem 1.5rem;border-bottom:1px solid var(--g-hair);vertical-align:middle;}
table.t tbody tr{transition:background .25s var(--ease);}
table.t tbody tr:hover{background:var(--g1-bg);}
table.t tbody tr:last-child td{border-bottom:0;}
.empty{padding:3.5rem 1.5rem;text-align:center;color:var(--fg-dim);}
.empty svg{width:2rem;height:2rem;margin-inline:auto;opacity:.4;stroke-width:1.5;}

/* ══════════════════════ ШАССИ АДМИНКИ ══════════════════════ */
.shell{display:flex;min-height:100svh;}
.side{position:fixed;inset-block:0;left:0;z-index:50;width:var(--sidebar-w);
  display:flex;flex-direction:column;padding:1.5rem 1rem 1rem;gap:.125rem;overflow:hidden;
  background:var(--g2-bg);backdrop-filter:blur(30px) saturate(1.8);
  -webkit-backdrop-filter:blur(30px) saturate(1.8);
  border-right:1px solid var(--g-hair);
  transform:translateX(-100%);transition:transform .5s var(--ease);}
.side.open{transform:none;}
/* Скроллится только список разделов. Иначе логотип и карточка админа уезжают
   вместе с ним, а на низком окне карточка просто срезается снизу.             */
.side-nav{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  display:flex;flex-direction:column;gap:.125rem;margin:0 -.25rem;padding:0 .25rem;}
.side-foot{flex:none;padding-top:1.25rem;}
.main-col{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;}
@media(min-width:1280px){.side{transform:none;}.main-col{margin-left:var(--sidebar-w);}}
.scrim{position:fixed;inset:0;z-index:40;background:var(--scrim);backdrop-filter:blur(3px);}
@media(min-width:1280px){.scrim{display:none;}}

.logo{display:flex;align-items:center;gap:.75rem;padding:.25rem .5rem 1.5rem;}
.logo-mark{width:2.375rem;height:2.375rem;border-radius:.6875rem;flex:none;
  display:grid;place-items:center;background:var(--accent);color:var(--accent-ink);
  font-family:var(--font-display);font-weight:900;font-size:.9375rem;letter-spacing:-.04em;}
.logo-name{font-family:var(--font-display);font-weight:800;letter-spacing:-.03em;
  color:var(--fg-max);line-height:1.1;}

.nav-h{margin-top:1.375rem;padding:0 .75rem .5rem;font-size:var(--t-xs);font-weight:700;
  text-transform:uppercase;letter-spacing:.14em;color:var(--fg-dim);opacity:.7;}
.nav-i{position:relative;display:flex;align-items:center;gap:.75rem;
  padding:.6875rem .75rem;border-radius:var(--r-md);color:var(--fg);
  font-size:var(--t-sm);font-weight:600;letter-spacing:-.01em;
  transition:background .3s var(--ease),color .3s var(--ease);}
.nav-i svg{width:1.125rem;height:1.125rem;flex:none;stroke-width:1.9;opacity:.8;}
.nav-i:hover{background:var(--g1-bg);color:var(--fg-max);}
.nav-i.on{background:var(--g3-bg);color:var(--fg-max);}
/* Активный пункт отмечен засечкой у края, а не заливкой во всю ширину. */
.nav-i.on::before{content:'';position:absolute;left:-1rem;top:50%;translate:0 -50%;
  width:3px;height:1.25rem;border-radius:0 3px 3px 0;background:var(--accent);}
.nav-i.on svg{opacity:1;color:var(--accent);}
.nav-i .n{margin-left:auto;font-size:var(--t-xs);font-weight:600;color:var(--fg-dim);
  font-variant-numeric:tabular-nums;}

.topbar{position:sticky;top:0;z-index:30;display:flex;align-items:center;gap:1rem;
  padding:.9375rem 1.25rem;background:var(--g2-bg);border-bottom:1px solid var(--g-hair);
  backdrop-filter:blur(24px) saturate(1.7);-webkit-backdrop-filter:blur(24px) saturate(1.7);}
@media(min-width:768px){.topbar{padding:1rem 2rem;}}
.main{flex:1;padding:1.5rem 1.25rem 4rem;}
@media(min-width:768px){.main{padding:2rem 2rem 5rem;}}
.crumbs{display:flex;align-items:center;gap:.4375rem;font-size:var(--t-xs);
  font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--fg-dim);}
.crumbs a:hover{color:var(--fg-max);}
.page-head{display:flex;align-items:flex-end;justify-content:space-between;
  gap:1.5rem;flex-wrap:wrap;margin-bottom:1.875rem;}

/* ══════════════════════ МЕТРИКИ ══════════════════════ */
.stat{padding:1.5rem;display:flex;flex-direction:column;gap:.875rem;min-height:9.5rem;
  justify-content:space-between;}
.stat-top{display:flex;align-items:flex-start;justify-content:space-between;gap:.75rem;}
.stat-ico{width:2.25rem;height:2.25rem;border-radius:.625rem;flex:none;display:grid;
  place-items:center;background:var(--g3-bg);color:var(--accent);}
.stat-ico svg{width:1.0625rem;height:1.0625rem;stroke-width:2;}
.stat-val{font-family:var(--font-display);font-size:clamp(2rem,4.4vw,2.875rem);
  font-weight:900;letter-spacing:-.05em;line-height:.9;color:var(--fg-max);
  font-variant-numeric:tabular-nums;}
.stat-lbl{font-size:var(--t-xs);font-weight:600;text-transform:uppercase;
  letter-spacing:.11em;color:var(--fg-dim);}

/* ══════════════════════ ПРОГРЕСС ══════════════════════ */
.bar{height:.3125rem;border-radius:var(--r-pill);background:var(--g3-bg);overflow:hidden;}
.bar>i{display:block;height:100%;border-radius:inherit;
  background:linear-gradient(90deg,var(--accent),var(--lime-300));
  box-shadow:0 0 14px -2px var(--lime-glow);
  transform-origin:left;animation:grow 1.3s var(--ease-out) both;}
@keyframes grow{from{transform:scaleX(0);}}

/* ══════════════════════ ЛЕНТА УРОКОВ ══════════════════════ */
.lesson{display:flex;align-items:center;gap:1rem;padding:1rem 1.5rem;
  border-bottom:1px solid var(--g-hair);transition:background .28s var(--ease);}
.lesson:last-child{border-bottom:0;}
.lesson:hover{background:var(--g1-bg);}
.lesson-n{width:1.875rem;height:1.875rem;border-radius:50%;flex:none;display:grid;
  place-items:center;font-family:var(--font-display);font-size:var(--t-xs);font-weight:800;
  background:var(--g3-bg);color:var(--fg-dim);}
.lesson.done .lesson-n{background:var(--ok-dim);color:var(--ok);}
.lesson.now .lesson-n{background:var(--accent);color:var(--accent-ink);}
.lesson-t{font-size:var(--t-md);font-weight:700;color:var(--fg-max);letter-spacing:-.015em;}
.lesson-m{font-size:var(--t-xs);color:var(--fg-dim);margin-top:.125rem;}

/* ══════════════════════ ШАГИ ТЕХНИКИ ══════════════════════ */
.steps{counter-reset:s;list-style:none;padding:0;margin:0;display:flex;
  flex-direction:column;gap:1.125rem;}
.steps li{counter-increment:s;display:flex;gap:1rem;font-family:var(--font-text);
  font-size:var(--t-md);line-height:1.65;}
.steps li::before{content:counter(s,decimal-leading-zero);flex:none;
  font-family:var(--font-display);font-size:var(--t-xs);font-weight:800;
  color:var(--accent);padding-top:.25rem;letter-spacing:.02em;}

/* Бесконечная лента: используется на витрине курсов и в фоне гейта. */
.ticker{display:flex;gap:1rem;width:max-content;animation:slide 64s linear infinite;}
@keyframes slide{to{transform:translateX(-50%);}}

/* Карточка служебного входа (админка): та же метрика, что у гейта. */
.gate-card{width:100%;max-width:27rem;}

/* ══════════════════════ ГЕЙТ ВХОДА ══════════════════════ */
/* Одна плита по центру экрана. Две половины без рамки читались как
   недоделанный макет: карточка висела в пустом поле. Здесь пустоты нет —
   есть объект и воздух вокруг него. Слева плита живёт (фон едет, карточки
   сменяются, свет проходит), справа — ввод кода. */
.gate{min-height:100svh;display:grid;place-items:center;
  padding:clamp(1rem,3vw,2.5rem);}
.gate-panel{width:100%;max-width:62rem;overflow:hidden;display:grid;
  grid-template-columns:1fr;box-shadow:var(--g-shadow-hi);
  animation:gate-in .85s var(--ease) both;}
@media(min-width:900px){
  .gate-panel{grid-template-columns:1.02fr .98fr;min-height:min(38rem,88svh);}
}
/* Уход страницы после верного кода: переход, а не мигание белым. */
.gate-panel.is-go{animation:gate-out .45s var(--ease) forwards;}
@keyframes gate-in{from{opacity:0;transform:translateY(20px) scale(.985);}}
@keyframes gate-out{to{opacity:0;transform:translateY(-12px) scale(.985);}}

/* ── левая половина: витрина ── */
.gate-vis{position:relative;overflow:hidden;height:11rem;
  border-bottom:1px solid var(--g-hair);
  background:linear-gradient(165deg,rgba(255,255,255,.07),transparent 58%);}
@media(min-width:900px){
  .gate-vis{height:auto;border-bottom:0;border-right:1px solid var(--g-hair);}
}
/* Фон — сам контент каталога: три ленты силуэтов, едущих встречно. */
.vis-back{position:absolute;inset:-16% -10%;display:flex;gap:.875rem;
  transform:rotate(-9deg);opacity:.15;filter:blur(1.5px);}
.vis-col{flex:1;display:flex;flex-direction:column;gap:.875rem;}
.vis-col.fwd{animation:vis-up 44s linear infinite;}
.vis-col.rev{animation:vis-down 52s linear infinite;}
.vis-col i{display:block;width:100%;aspect-ratio:1;border-radius:var(--r-md);
  background:var(--g3-bg) center/76% no-repeat;filter:var(--art-filter);}
@keyframes vis-up{to{transform:translateY(-50%);}}
@keyframes vis-down{from{transform:translateY(-50%);}}

/* Круги-импульсы: подсказывают центр композиции, не отвлекая. */
.vis-rings{position:absolute;inset:0;display:grid;place-items:center;
  pointer-events:none;z-index:1;}
.vis-rings i{position:absolute;width:15rem;height:15rem;border-radius:50%;
  border:1px solid var(--g-edge-hi);opacity:0;
  animation:vis-ring 5.4s var(--ease) infinite;}
.vis-rings i:nth-child(2){animation-delay:1.8s;}
.vis-rings i:nth-child(3){animation-delay:3.6s;}
@keyframes vis-ring{
  0%{transform:scale(.5);opacity:0;} 16%{opacity:.4;}
  100%{transform:scale(1.85);opacity:0;}}

/* Колода: шесть кадров сменяют друг друга по кругу, сдвиг задаёт --i. */
.vis-deck{position:absolute;inset:0;display:grid;place-items:center;z-index:2;}
.vis-card{position:absolute;margin:0;height:74%;aspect-ratio:3/4;
  border-radius:var(--r-lg);overflow:hidden;opacity:0;
  background:var(--g2-bg);border:1px solid var(--g-edge-hi);
  backdrop-filter:blur(18px) saturate(1.5);-webkit-backdrop-filter:blur(18px) saturate(1.5);
  box-shadow:var(--g-shadow-hi),0 0 70px -24px var(--lime-glow);
  animation:vis-card 21s var(--ease) infinite;
  animation-delay:calc(var(--i) * 3.5s - 21s);}
@media(min-width:900px){.vis-card{height:min(58%,17rem);}}
.vis-card img{width:100%;height:100%;object-fit:contain;padding:1.125rem;
  filter:var(--art-filter);-webkit-user-drag:none;user-select:none;}
@keyframes vis-card{
  0%  {opacity:0;transform:translate3d(0,16px,0) scale(.94) rotate(-3deg);}
  4%  {opacity:1;transform:none;}
  14% {opacity:1;transform:none;}
  19% {opacity:0;transform:translate3d(0,-16px,0) scale(.97) rotate(2.5deg);}
  100%{opacity:0;transform:translate3d(0,16px,0) scale(.94) rotate(-3deg);}}

/* Цифры вместо обещаний: сколько всего внутри. */
.vis-meta{position:absolute;left:1.375rem;right:1.375rem;bottom:1.375rem;z-index:3;
  display:none;flex-wrap:wrap;gap:.5rem;}
@media(min-width:900px){.vis-meta{display:flex;}}
.vis-pill{display:inline-flex;align-items:baseline;gap:.4375rem;
  padding:.4375rem .8125rem;border-radius:var(--r-pill);
  background:var(--g3-bg);border:1px solid var(--g-edge);
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
  font-size:var(--t-xs);font-weight:700;color:var(--fg-dim);
  text-transform:uppercase;letter-spacing:.1em;}
.vis-pill .num{font-size:var(--t-md);}

/* Луч света раз в несколько секунд — «сканирование» кода. */
.vis-scan{position:absolute;inset:0;z-index:2;pointer-events:none;opacity:.5;
  background:linear-gradient(180deg,transparent 43%,
    color-mix(in srgb,var(--accent) 26%,transparent) 50%,transparent 57%);
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 22%,#000 78%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 22%,#000 78%,transparent);
  animation:vis-scan 8s var(--ease) infinite;}
@keyframes vis-scan{0%{transform:translateY(-70%);}
  50%{transform:translateY(70%);}100%{transform:translateY(70%);}}
/* Виньетка держит витрину внутри плиты, а не расползается к краям. */
.gate-vis::after{content:'';position:absolute;inset:0;z-index:4;pointer-events:none;
  background:radial-gradient(120% 85% at 50% 45%,transparent 38%,
             color-mix(in srgb,var(--ink) 62%,transparent) 100%);}
:root.light .gate-vis::after{
  background:radial-gradient(120% 85% at 50% 45%,transparent 42%,
             rgba(239,239,232,.6) 100%);}

/* ── правая половина: шапка, ввод, подпись ── */
.gate-body{display:flex;flex-direction:column;gap:1.25rem;
  padding:clamp(1.5rem,3.2vw,2.5rem);}
.gate-top{display:flex;align-items:center;justify-content:space-between;gap:1rem;}
.gate-top .logo{padding:0;}
.logo-sub{display:block;font-size:.5625rem;font-weight:700;letter-spacing:.2em;
  text-transform:uppercase;}
.gate-main{flex:1;display:flex;flex-direction:column;justify-content:center;
  min-width:0;}
.gate-note{max-width:30rem;font-size:var(--t-sm);margin-bottom:1.375rem;}
.gate-err{margin-bottom:1rem;animation:shake .5s var(--ease);}
.gate-bottom{display:flex;flex-direction:column;gap:.75rem;}
.gate-bottom .alert{padding:.75rem .875rem;font-size:var(--t-xs);line-height:1.5;}
.gate-bottom .alert svg{width:1rem;height:1rem;}
/* ── вход в бота ──
   Вторая дверь на гейте: кода нет как раз у тех, кто пришёл впервые. Раньше
   тут был самолётик в кружке — такой значок можно наклеить на любой сайт.
   Теперь на кнопке лицо: ровно тот портрет, который человек увидит в Telegram,
   когда откроет диалог. Обещание становится конкретным — пишешь не «боту»,
   а вот ей, и по аватарке потом узнаёшь чат в списке.
   Из того же файла собран и свет под кнопкой: 24×24 заранее размытых
   пикселя, которые браузер растягивает в пятно. Цвета подложки не подобраны
   руками — они буквально взяты из аватарки, поэтому кнопка выглядит вросшей
   в стекло, а не наклеенной поверх. */
.bot-call{position:relative;isolation:isolate;overflow:hidden;
  display:flex;align-items:center;gap:.875rem;
  padding:.75rem .875rem;border-radius:var(--r-md);
  background:var(--g3-bg);border:1px solid var(--g-edge);
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
  color:var(--fg);text-decoration:none;
  /* Разная скорость намеренно: отклик на нажатие мгновенный,
     свет и цвет догоняют спокойно. */
  transition:border-color .3s var(--ease),box-shadow .3s var(--ease),
             transform .16s var(--ease);
  animation:bot-rise .7s var(--ease) .55s both;}

/* Пятно от портрета. Круг с мягким краем: маска гасит его раньше, чем он
   дойдёт до рамки, иначе на светлой теме проступает квадрат картинки. */
.bot-call::before{content:"";position:absolute;z-index:-2;pointer-events:none;
  left:-2rem;top:50%;width:12rem;height:12rem;margin-top:-6rem;border-radius:50%;
  background:url("../brand/bot-wash.webp") center/cover no-repeat;
  opacity:.42;transition:opacity .4s var(--ease);
  -webkit-mask-image:radial-gradient(closest-side,#000 25%,transparent 100%);
          mask-image:radial-gradient(closest-side,#000 25%,transparent 100%);}
:root.light .bot-call::before{opacity:.24;}

.bot-call-av{position:relative;flex:none;width:2.75rem;height:2.75rem;}
.bot-call-av img{display:block;width:100%;height:100%;border-radius:50%;
  object-fit:cover;background:var(--ink-3);
  transition:transform .35s var(--ease);
  -webkit-user-drag:none;user-select:none;}
/* Ободок статичный — он держит портрет на стекле. */
.bot-call-av::before{content:"";position:absolute;inset:-3px;border-radius:50%;
  border:1.5px solid color-mix(in srgb,var(--accent) 45%,transparent);
  transition:border-color .3s var(--ease);}
/* А волна раз в семь секунд уходит от ободка и гаснет: так в мессенджере
   выглядит «я на связи». Это единственное, что на гейте движется само. */
.bot-call-av::after{content:"";position:absolute;inset:-3px;border-radius:50%;
  border:1.5px solid var(--accent);opacity:0;pointer-events:none;
  animation:bot-pulse 7s var(--ease) 2s infinite;}

/* Бейдж досказывает, куда ведёт кнопка: лицо — кто, самолётик — где. */
.bot-call-badge{position:absolute;z-index:1;right:-3px;bottom:-3px;
  display:grid;place-items:center;width:1.125rem;height:1.125rem;
  border-radius:50%;background:var(--accent);color:var(--accent-ink);
  box-shadow:0 0 0 2px var(--bg);
  transition:transform .3s var(--ease);
  animation:bot-badge .45s var(--ease) 1.05s both;}
.bot-call-badge svg{width:.6875rem;height:.6875rem;}

.bot-call-txt{flex:1;min-width:0;display:flex;flex-direction:column;gap:.125rem;}
.bot-call-t{font-size:var(--t-sm);font-weight:600;line-height:1.25;}
.bot-call-s{font-size:var(--t-xs);color:var(--fg-dim);line-height:1.35;}
.bot-call-arr{flex:none;width:1rem;height:1rem;color:var(--fg-dim);
  transition:transform .3s var(--ease),color .3s var(--ease);}

/* Курсор — только там, где он настоящий: на тач-экране :hover залипает
   после тапа, и кнопка осталась бы подсвеченной навсегда. */
@media(hover:hover) and (pointer:fine){
  .bot-call:hover{transform:translate3d(0,-2px,0);
    border-color:color-mix(in srgb,var(--accent) 62%,transparent);
    box-shadow:0 0 0 4px color-mix(in srgb,var(--accent) 10%,transparent),
               0 14px 34px -20px var(--lime-glow);}
  .bot-call:hover::before{opacity:.6;}
  :root.light .bot-call:hover::before{opacity:.36;}
  .bot-call:hover .bot-call-av img{transform:scale(1.07);}
  .bot-call:hover .bot-call-av::before{border-color:var(--accent);}
  .bot-call:hover .bot-call-badge{transform:scale(1.12);}
  .bot-call:hover .bot-call-badge svg{animation:bot-fly .62s var(--ease);}
  .bot-call:hover .bot-call-arr{transform:translateX(4px);color:var(--accent);}
}
/* Клавиатура должна получать ту же подсветку, что и мышь, но без полёта. */
.bot-call:focus-visible{outline:none;transform:translate3d(0,-2px,0);
  border-color:var(--accent);
  box-shadow:0 0 0 4px color-mix(in srgb,var(--accent) 16%,transparent),
             0 14px 34px -20px var(--lime-glow);}
.bot-call:focus-visible::before{opacity:.6;}
:root.light .bot-call:focus-visible::before{opacity:.36;}
.bot-call:focus-visible .bot-call-av img{transform:scale(1.07);}
.bot-call:focus-visible .bot-call-av::before{border-color:var(--accent);}
.bot-call:focus-visible .bot-call-arr{transform:translateX(4px);color:var(--accent);}
/* Нажатие: палец продавливает стекло и отпускает — 120 мс, не дольше. */
.bot-call:active{transform:translate3d(0,0,0) scale(.985);
  transition-duration:.12s;}

@keyframes bot-rise{from{opacity:0;transform:translate3d(0,10px,0);}}
@keyframes bot-badge{from{opacity:0;transform:scale(.4);}}
/* Шесть седьмых цикла кольца нет — иначе рядом с полем ввода кода
   это была бы мигалка, а не признак жизни. */
@keyframes bot-pulse{
  0%{opacity:.55;transform:scale(1);}
  16%,100%{opacity:0;transform:scale(1.42);}}
/* Самолётик уходит за верхний правый угол и возвращается из нижнего левого:
   тот же самолётик, а не два — поэтому между кадрами он невидим. */
@keyframes bot-fly{
  0%{transform:translate3d(0,0,0);opacity:1;}
  40%{transform:translate3d(1rem,-1rem,0) scale(.8);opacity:0;}
  41%{transform:translate3d(-.9rem,.9rem,0) scale(.8);opacity:0;}
  100%{transform:translate3d(0,0,0);opacity:1;}}

/* тот же вход для тех, кто уже внутри курса — но в подвале, вполголоса */
/* ── связь с ботом из подвала ──
   Была подчёркнутая ссылка высотой 20 px — на телефоне в неё не попасть.
   Теперь это пилюля с аватаркой: ростом 44 px, то есть минимальная цель
   пальца, и с собственной обводкой, чтобы её видели как кнопку, а не как
   строчку выходных данных рядом. Подчёркивание из `.foot a` снимаем явно:
   у селектора `.foot a` вес выше, чем у одиночного класса. */
.foot-bot{display:inline-flex;align-items:center;gap:.625rem;
  min-height:2.75rem;padding:.375rem .9375rem .375rem .375rem;
  border-radius:var(--r-pill);border:1px solid var(--g-edge);
  background:var(--g3-bg);font-size:var(--t-sm);font-weight:600;
  color:var(--fg);line-height:1;
  transition:color .3s var(--ease),border-color .3s var(--ease),
    background .3s var(--ease),transform .15s var(--ease);}
.foot .foot-bot{text-decoration:none;}
.foot-bot img{width:2rem;height:2rem;border-radius:50%;object-fit:cover;
  background:var(--ink-3);box-shadow:0 0 0 1px var(--g-edge-hi);
  transition:transform .3s var(--ease),box-shadow .3s var(--ease);
  -webkit-user-drag:none;user-select:none;}
.foot-bot:hover,.foot-bot:focus-visible{color:var(--accent);
  border-color:color-mix(in srgb,var(--accent) 45%,transparent);
  background:var(--g2-bg);}
.foot-bot:active{transform:scale(.97);}
.foot-bot:focus-visible{outline:2px solid var(--accent);outline-offset:2px;}
.foot-bot:hover img,.foot-bot:focus-visible img{transform:scale(1.08);
  box-shadow:0 0 0 1px color-mix(in srgb,var(--accent) 70%,transparent);}
@media(max-width:600px){
  /* На узком экране подвал складывается в столбец: кнопка идёт первой
     и растягивается на всю ширину — её ищут чаще, чем выходные данные. */
  .foot>.wrap{flex-direction:column;align-items:stretch;text-align:center;
    gap:.875rem;}
  .foot-bot{order:-1;justify-content:center;min-height:3rem;
    padding-inline:.375rem 1.125rem;font-size:var(--t-md);}
  .foot-bot img{width:2.25rem;height:2.25rem;}
}

@keyframes shake{
  10%,90%{transform:translateX(-2px);} 20%,80%{transform:translateX(4px);}
  30%,50%,70%{transform:translateX(-7px);} 40%,60%{transform:translateX(7px);}}

/* ── сегментированный ввод кода ──
   Три группы по четыре символа: рука не считает позиции, фокус едет сам.
   Префикс FIT напечатан, а не вводится — его всё равно набирают все. */
.code-set{position:relative;display:flex;align-items:center;justify-content:center;
  gap:.25rem;padding:1rem .625rem 1.25rem;margin-bottom:1rem;
  border-radius:var(--r-lg);background:var(--g3-bg);border:1px solid var(--g-edge);
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
  transition:border-color .35s var(--ease),box-shadow .35s var(--ease);}
.code-set:focus-within{border-color:var(--accent);
  box-shadow:0 0 0 4px color-mix(in srgb,var(--accent) 14%,transparent),
             0 0 52px -16px var(--lime-glow);}
.code-set.is-bad{border-color:var(--bad);
  box-shadow:0 0 0 4px color-mix(in srgb,var(--bad) 14%,transparent);
  animation:shake .5s var(--ease);}
.code-set.is-full{border-color:var(--accent);}
.code-pre,.code-dash,.code-cell{font-family:var(--font-mono);font-weight:700;
  font-size:clamp(.9375rem,2.9vw,1.1875rem);line-height:1.3;}
.code-pre{color:var(--fg-dim);letter-spacing:.12em;}
.code-dash{color:var(--fg-dim);opacity:.45;padding:0 .0625rem;}
.code-cell{width:5.1ch;min-width:0;padding:.4375rem .125rem;border:0;border-radius:var(--r-sm);
  background:color-mix(in srgb,var(--fg-max) 6%,transparent);
  color:var(--fg-max);letter-spacing:.12em;text-align:center;text-transform:uppercase;
  caret-color:var(--accent);transition:background .25s var(--ease);}
.code-cell:hover{background:color-mix(in srgb,var(--fg-max) 9%,transparent);}
.code-cell:focus{outline:0;background:color-mix(in srgb,var(--accent) 12%,transparent);}
.code-cell::placeholder{color:var(--fg-dim);opacity:.35;letter-spacing:.1em;}
/* Подчёркивание собирается из центра, когда поле получает фокус. */
.code-line{position:absolute;left:50%;bottom:.5625rem;height:2px;
  width:calc(100% - 2.25rem);border-radius:2px;opacity:0;
  transform:translateX(-50%) scaleX(0);
  background:linear-gradient(90deg,transparent,var(--accent),transparent);
  transition:transform .45s var(--ease),opacity .45s var(--ease);}
.code-set:focus-within .code-line{opacity:1;transform:translateX(-50%) scaleX(1);}
.code-set.is-bad .code-line{background:linear-gradient(90deg,transparent,var(--bad),transparent);}

.gate-go{margin-top:.125rem;}
.gate-go.is-busy{pointer-events:none;}
.gate-go.is-busy .arr{display:none;}

/* ── выбор языка: <details>, потому что CSP запрещает инлайновый скрипт ── */
.langpick{position:relative;flex:none;}
.langpick>summary{display:inline-flex;align-items:center;gap:.4375rem;cursor:pointer;
  list-style:none;padding:.4375rem .6875rem;border-radius:var(--r-pill);
  background:var(--g3-bg);border:1px solid var(--g-edge);color:var(--fg);
  font-size:var(--t-xs);font-weight:700;
  transition:border-color .3s var(--ease),color .3s var(--ease);}
.langpick>summary::-webkit-details-marker{display:none;}
.langpick>summary::marker{content:'';}
.langpick>summary:hover{border-color:var(--g-edge-hi);color:var(--fg-max);}
.langpick>summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px;}
.langpick-flag{font-size:.9375rem;line-height:1;display:inline-flex;align-items:center;}
/* Нарисованный флаг вместо эмодзи: подгоняем под кегль соседних эмодзи,
   чтобы строка в списке языков не прыгала. */
.flag-svg{width:1.15em;height:calc(1.15em * 2 / 3);border-radius:.09em;display:block;}
.langpick-now{max-width:7rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.langpick-arr{width:.8em;height:.8em;opacity:.6;transition:transform .3s var(--ease);}
.langpick[open] .langpick-arr{transform:rotate(180deg);}
.langpick-menu{position:absolute;top:calc(100% + .5rem);z-index:40;
  min-width:11.5rem;max-height:17rem;overflow:auto;padding:.375rem;
  border-radius:var(--r-md);background:var(--g2-bg);border:1px solid var(--g-edge);
  box-shadow:var(--g-shadow-hi);
  backdrop-filter:blur(var(--g-blur));-webkit-backdrop-filter:blur(var(--g-blur));
  animation:langpop .24s var(--ease);}
.langpick-right .langpick-menu{right:0;}
.langpick-left  .langpick-menu{left:0;}
.langpick-i{display:flex;align-items:center;gap:.5rem;min-height:2.75rem;
  padding:.5rem .625rem;
  border-radius:var(--r-sm);font-size:var(--t-sm);color:var(--fg);
  transition:background .2s var(--ease),color .2s var(--ease);}
.langpick-i:hover{background:var(--g3-bg);color:var(--fg-max);}
.langpick-i.on{color:var(--accent);}
.langpick-tick{width:.9em;height:.9em;margin-left:auto;}
@keyframes langpop{from{opacity:0;transform:translateY(-6px) scale(.97);}}

/* Без анимаций колода замирает на первом кадре, а не исчезает целиком. */
@media(prefers-reduced-motion:reduce){
  .vis-card{display:none;}
  .vis-card:first-child{display:block;opacity:1;}
  .vis-scan,.vis-rings{display:none;}
}

/* ══════════════════════ ГЕРОЙ ══════════════════════ */
.hero{position:relative;padding:3rem 0 2.5rem;}
@media(min-width:768px){.hero{padding:4.5rem 0 3.5rem;}}
.hero-meta{display:flex;flex-wrap:wrap;gap:2rem;margin-top:2rem;}
.hero-meta div{display:flex;flex-direction:column;gap:.1875rem;}
.hero-meta .num{font-size:1.75rem;}
.hero-meta .eyebrow{font-size:.625rem;}

.cover{position:relative;aspect-ratio:4/3;overflow:hidden;border-radius:var(--r-lg);}
.cover-grid{position:absolute;inset:0;display:grid;grid-template-columns:repeat(3,1fr);
  grid-template-rows:repeat(2,1fr);}
.cover-grid img{width:100%;height:100%;object-fit:contain;padding:.375rem;
  filter:var(--art-filter);}
.cover-tint{position:absolute;inset:0;z-index:1;
  background:linear-gradient(165deg,transparent 46%,var(--cover-fade) 88%);}
.cover-tag{position:absolute;left:1rem;bottom:1rem;z-index:2;}
/* Обложка курса — коллаж с глубиной: ведущая фигура выходит за край,
   остальные отступают прозрачностью, а не размером плитки.                     */
.collage{position:absolute;inset:0;}
.collage img{position:absolute;object-fit:contain;filter:var(--art-filter);
  transition:transform .9s var(--ease);}
.c-a{right:5%;top:6%;height:88%;opacity:1;}
.c-b{left:3%;bottom:2%;height:64%;opacity:.4;}
.c-c{left:30%;top:10%;height:44%;opacity:.18;}
.course-card:hover .c-a{transform:translateX(-1.5%) scale(1.03);}
.course-card:hover .c-b{transform:translateX(2%) scale(1.02);}

.cover.mini{position:relative;overflow:visible;}
.cover.mini img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;
  filter:var(--art-filter);}
.cover.mini .c-b{transform:translate(-14%,6%) scale(.72);opacity:.34;}
.cover.mini .c-a{transform:translate(8%,-2%);opacity:1;}

.course-card:hover .cover-grid{transform:scale(1.04);transition:transform .8s var(--ease);}

/* ══════════════════════ ПАГИНАЦИЯ ══════════════════════ */
.pager{display:flex;gap:.375rem;flex-wrap:wrap;align-items:center;justify-content:center;}

/* Цифры остаются квадратными, «дальше» тянется по своему слову: min-width —
   это минимум, а не размер. inline-flex, а не grid: у кнопки «дальше» два
   ребёнка — подпись и стрелка, — и grid уносил стрелку на вторую строку,
   разрывая рамку. nowrap не даёт «Siguiente» или «Dalej» переноситься. */
.pager a,.pager span{min-width:2.375rem;min-height:2.375rem;
  display:inline-flex;align-items:center;justify-content:center;gap:.4rem;
  white-space:nowrap;padding-inline:.625rem;border-radius:var(--r-md);
  font-size:var(--t-sm);font-weight:700;line-height:1;
  background:var(--g1-bg);border:1px solid var(--g-edge);transition:all .28s var(--ease);}
.pager a:hover{border-color:var(--accent);color:var(--fg-max);}
.pager .on{background:var(--accent);border-color:var(--accent);color:var(--accent-ink);}
.pager .next{padding-inline:.875rem;}
.pager .next .arr{flex:none;transition:transform .35s var(--ease);}
.pager .next:hover .arr{transform:translateX(3px);}

/* ══════════════════════ ПОЯВЛЕНИЕ ══════════════════════
   Появление ставит JS через IntersectionObserver, добавляя .in.
   Без JS содержимое видно сразу — прогрессивное улучшение, а не зависимость.  */
.rise{opacity:0;transform:translateY(18px);
  transition:opacity .85s var(--ease-out),transform .85s var(--ease-out);}
.rise.in{opacity:1;transform:none;}
.rise:nth-child(2){transition-delay:.07s}.rise:nth-child(3){transition-delay:.14s}
.rise:nth-child(4){transition-delay:.21s}.rise:nth-child(5){transition-delay:.28s}
.rise:nth-child(6){transition-delay:.35s}
.no-js .rise{opacity:1;transform:none;}

.scrollbar::-webkit-scrollbar{width:5px;height:5px;}
.scrollbar::-webkit-scrollbar-thumb{background:var(--g-edge);border-radius:var(--r-pill);}
.scrollbar::-webkit-scrollbar-track{background:transparent;}

/* ══════════════════════ ШАПКА САЙТА ══════════════════════
   То же шасси, что и topbar админки, но контент выровнен по .wrap:
   единый материал на сайте и в админке — иначе это два разных продукта. */
.site-head{position:sticky;top:0;z-index:30;background:var(--g2-bg);
  border-bottom:1px solid var(--g-hair);
  backdrop-filter:blur(24px) saturate(1.7);-webkit-backdrop-filter:blur(24px) saturate(1.7);}
.site-head>.wrap{display:flex;align-items:center;gap:1rem;padding-block:.75rem;}
.site-head .logo{padding:0;}
.site-act{display:flex;align-items:center;gap:.4375rem;margin-left:auto;}
.site-nav{display:flex;gap:.25rem;}
.site-nav a{padding:.5rem .875rem;border-radius:var(--r-pill);font-size:var(--t-sm);
  font-weight:600;color:var(--fg-dim);white-space:nowrap;
  transition:color .3s var(--ease),background .3s var(--ease);}
.site-nav a:hover{color:var(--fg-max);}
.site-nav a.on{background:var(--g3-bg);color:var(--fg-max);}
@media(max-width:700px){
  .site-head>.wrap{flex-wrap:wrap;gap:.5rem;}
  .site-nav{order:3;width:100%;overflow-x:auto;scrollbar-width:none;}
  .site-nav::-webkit-scrollbar{display:none;}
  .site-nav a{min-height:2.5rem;display:inline-flex;align-items:center;}
}
@media(max-width:560px){
  /* Шапка липкая, и в три ряда она съедала пятую часть экрана. Убираем
     название языка (флага достаточно, полный список всё равно в меню)
     и поджимаем поля — остаётся два ряда вместо трёх. */
  .site-head>.wrap{padding-block:.5rem;gap:.4375rem;}
  .langpick-now,.langpick-arr{display:none;}
  .langpick>summary{padding:.4375rem .5625rem;}
  .site-head .logo-mark{width:1.875rem;height:1.875rem;font-size:.8125rem;}
  .site-head .logo-name{font-size:var(--t-md);}
  /* Срок доступа уезжает во второй ряд, к навигации: в первом он вытеснял
     кнопку выхода на собственную строку, и шапка занимала три ряда. */
  .site-head .badge{order:4;margin-left:auto;padding:.25rem .5rem;font-size:.625rem;}
  .site-nav{width:auto;flex:1 1 auto;min-width:0;}
}
.foot{margin-top:4.5rem;padding:2.5rem 0 3rem;border-top:1px solid var(--g-hair);
  font-size:var(--t-xs);color:var(--fg-dim);}
.foot a{text-decoration:underline;text-decoration-color:var(--g-edge);text-underline-offset:.2em;}

/* ── подпись автора ──
   Одна строка, одинаковая на сайте, на гейте и в сайдбаре админки: чьё это
   сделано. Моноширинный набор и приглушённый цвет — чтобы она читалась как
   выходные данные, а не как ещё один элемент интерфейса. */
.foot-by{font-size:var(--t-xs);color:var(--fg-dim);letter-spacing:.01em;
  white-space:nowrap;}
.side-foot .foot-by{margin:.75rem 0 0;text-align:center;opacity:.7;}
.gate-by{padding-top:.25rem;text-align:center;color:var(--fg-dim);
  font-size:var(--t-xs);}

/* ── мелкие раскладочные утилиты: в прототипе это были inline-стили ── */
.actions{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;}
.gap-sm{gap:.5rem;} .gap-xs{gap:.25rem;} .gap-md{gap:1rem;}
.end{justify-content:flex-end;} .px-q{padding:0 .25rem .25rem;}
.align-end{align-items:flex-end;}
.sticky{position:sticky;top:1.5rem;}
.w-auto{width:auto;} .maxw-34{max-width:34rem;} .maxw-26{max-width:26rem;}
.fw-600{font-weight:600;} .px-1{padding-inline:1rem;}
.search{position:relative;flex:1 1 15rem;min-width:11rem;}

/* ── строка поиска по каталогу ──
   Селект инвентаря и кнопку «Найти» flex-обёртка на узком экране ставила
   тремя этажами: подпись инвентаря на одиннадцати языках бывает длинной,
   и строка рвалась ровно перед кнопкой. Сетка держит их в одном ряду —
   селект тянется по остатку, кнопка берёт свою ширину и не переносится. */
.ex-search{display:grid;grid-template-columns:minmax(0,1fr) auto;
  gap:.5rem;align-items:stretch;}
.ex-search input[type=hidden]{display:none;}
.ex-search .search{grid-column:1 / -1;flex:none;min-width:0;}
.ex-search .select{width:100%;min-width:0;text-overflow:ellipsis;}
.ex-search .btn{white-space:nowrap;}
@media(max-width:560px){
  /* подпись инвентаря длинная почти на всех языках — жмём поля,
     а не режем слово многоточием */
  .ex-search .select{padding-inline:.75rem 1.875rem;font-size:var(--t-sm);
    background-position:right .625rem center;}
}
@media(min-width:840px){
  .ex-search{grid-template-columns:minmax(11rem,1fr) minmax(0,auto) auto;}
  .ex-search .search{grid-column:auto;}
}
.search .input{padding-left:2.625rem;}
.search>svg{position:absolute;left:.9375rem;top:50%;translate:0 -50%;
  width:1.0625rem;height:1.0625rem;color:var(--fg-dim);pointer-events:none;}
.strip{padding:.75rem;}
.strip .art-box{width:5.5rem;flex:none;}
.mini-bar{width:5rem;flex:none;}

/* ── карточки курса: две геометрии одного материала ── */
.course-card{display:block;overflow:hidden;}
.course-card>.cover{aspect-ratio:16/9;border-radius:0;}
.course-card-row{display:flex;align-items:center;gap:1.125rem;padding:1rem;}
.course-card-row .cover{width:5.75rem;flex:none;aspect-ratio:1;}
.cover.sq{aspect-ratio:1;}
.art-frame{padding:1rem;}
.art-frame .art-box{border-radius:var(--r-md);}
.h-display-sm{font-size:clamp(2.25rem,5vw,3.75rem);}
.h-display-xs{font-size:clamp(1.875rem,4.2vw,3rem);}

/* ── редактор урока и списки админки ── */
.cover>img{width:100%;height:100%;object-fit:contain;padding:.375rem;
  background:var(--g3-bg);border-radius:inherit;}
.cover.ph{display:grid;place-items:center;background:var(--g3-bg);color:var(--fg-dim);}
.cover.ph svg{width:1.75rem;height:1.75rem;}
.ex-row{display:flex;align-items:flex-start;gap:.875rem;}
.ex-row .cover{width:4.5rem;flex:none;}
.ex-del{margin:-.5rem 0 .25rem;}
.w3{width:4.5rem;flex:none;}

/* ── страница ошибки: Http::errorPage рисует ровно это ── */
.fx-center{min-height:100svh;display:grid;place-items:center;padding:1.5rem;}
.fx-error{max-width:30rem;padding:2.25rem;text-align:center;}
.fx-error__code{font-family:var(--font-display);font-size:4.5rem;font-weight:900;
  line-height:1;letter-spacing:-.05em;color:var(--accent);}
.fx-error h1{margin:.5rem 0 .75rem;font-size:var(--t-h3);}
.fx-error p{color:var(--fg-dim);}

/* ── флеш-сообщения над формами ── */
.flash{margin-bottom:1.25rem;}

/* бургер: сайдбар прибит к экрану только с 1280px, ниже его открывают кнопкой */
.burger{display:inline-flex;}
@media(min-width:1280px){.burger{display:none;}}

@media(prefers-reduced-motion:reduce){
  /* Задержку гасим вместе с длительностью: иначе элемент с `both` держит
     свой кадр «до» — а это opacity:0 — и вместо мягкого входа получается
     пустое место, которое через полсекунды резко проявляется. */
  *,*::before,*::after{animation-duration:.01ms!important;animation-delay:0s!important;
    animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important;}
  .rise{opacity:1;transform:none;}
}

/* ══════════════════════ ТРЕНАЖЁР ══════════════════════
   Панель под картинкой упражнения: план, счётчик подходов, таймер отдыха.
   Четыре «лица» в одном месте — переключает app.js, сервер рисует первое.
   Главный индикатор — цепочка точек: она видна в любом состоянии и не
   зависит от JS, поэтому даже с отключёнными скриптами страница отвечает
   на вопрос «сколько я сегодня сделал». */
.trainer{position:relative;margin-top:1.25rem;padding:1.125rem;
  border-radius:var(--r-lg);background:var(--g3-bg);
  border:1px solid var(--g-edge);box-shadow:var(--g-shadow);
  backdrop-filter:blur(var(--g-blur)) saturate(1.6);}
.trainer-sm{margin-top:1rem;padding:.875rem 1rem;border-radius:var(--r-md);
  box-shadow:none;}

.tr-head{display:flex;align-items:center;justify-content:space-between;
  gap:.75rem;flex-wrap:wrap;margin-bottom:.75rem;}
.tr-head .eyebrow{display:inline-flex;align-items:center;gap:.4375rem;}
.tr-plan{font-family:var(--font-mono);font-size:var(--t-xs);
  color:var(--fg-dim);white-space:nowrap;}

/* цепочка подходов */
.tr-dots{display:flex;gap:.375rem;margin-bottom:.625rem;flex-wrap:wrap;}
.tr-dots i{width:1.75rem;height:.375rem;border-radius:var(--r-pill);
  background:var(--g-edge);transition:background .3s var(--ease),
  box-shadow .3s var(--ease),transform .3s var(--ease);}
.tr-dots i.on{background:var(--accent);box-shadow:0 0 12px -2px var(--lime-glow);}
/* только что закрытый подход — короткая вспышка, чтобы глаз её поймал */
@keyframes tr-pop{0%{transform:scaleX(.2);}60%{transform:scaleX(1.12);}100%{transform:scaleX(1);}}
.tr-dots i.pop{animation:tr-pop .42s var(--ease);}

.tr-last{font-size:var(--t-xs);color:var(--fg-dim);margin:0 0 .875rem;}

.tr-face{display:block;}
.tr-face[hidden]{display:none;}

/* подход идёт */
.tr-now{display:flex;align-items:baseline;justify-content:space-between;
  gap:.75rem;margin-bottom:.875rem;}
.tr-setno{font-family:var(--font-display);font-weight:800;font-size:var(--t-md);
  letter-spacing:var(--tracking-h);color:var(--fg-max);}
.tr-clock{font-family:var(--font-mono);font-size:1.75rem;font-weight:600;
  color:var(--accent);font-variant-numeric:tabular-nums;line-height:1;}

.tr-field{display:flex;align-items:center;justify-content:space-between;
  gap:.75rem;margin-bottom:.625rem;}
.tr-lab{font-size:var(--t-xs);color:var(--fg-dim);text-transform:lowercase;}
.tr-step{display:flex;align-items:center;gap:.25rem;}
.tr-pm{display:grid;place-items:center;width:2.75rem;height:2.75rem;flex:none;
  border:1px solid var(--g-edge);border-radius:var(--r-sm);cursor:pointer;
  background:var(--g3-bg);color:var(--fg-max);
  transition:background .2s var(--ease),transform .12s var(--ease);}
.tr-pm:hover{background:var(--g2-bg);}
.tr-pm:active{transform:scale(.92);}
.tr-pm svg{width:1.125rem;height:1.125rem;stroke-width:2.4;}
.tr-num{width:4.75rem;height:2.75rem;text-align:center;
  font-family:var(--font-mono);font-size:var(--t-md);font-weight:600;
  font-variant-numeric:tabular-nums;color:var(--fg-max);
  background:var(--g3-bg);border:1px solid var(--g-edge);
  border-radius:var(--r-sm);}
.tr-num:focus{outline:2px solid var(--accent);outline-offset:1px;}
.tr-num::-webkit-outer-spin-button,.tr-num::-webkit-inner-spin-button{
  -webkit-appearance:none;margin:0;}
.tr-num[type=number]{-moz-appearance:textfield;}

/* отдых: кольцо обратного отсчёта */
.tr-rest{text-align:center;}
.tr-ring{position:relative;width:8.5rem;height:8.5rem;margin:.25rem auto .75rem;}
.trainer-sm .tr-ring{width:6.5rem;height:6.5rem;}
.tr-ring svg{width:100%;height:100%;transform:rotate(-90deg);}
.tr-ring circle{fill:none;stroke-width:7;stroke-linecap:round;}
.tr-ring-bg{stroke:var(--g-edge);}
.tr-ring-fg{stroke:var(--accent);
  stroke-dasharray:326.7;stroke-dashoffset:0;
  transition:stroke-dashoffset .95s linear;
  filter:drop-shadow(0 0 8px var(--lime-glow));}
/* последние пять секунд — кольцо теплеет и дышит */
.tr-ring.soon .tr-ring-fg{stroke:var(--ember);
  filter:drop-shadow(0 0 10px rgba(255,107,74,.4));}
@keyframes tr-beat{0%,100%{transform:scale(1);}50%{transform:scale(1.06);}}
.tr-ring.soon .tr-ring-t{animation:tr-beat 1s var(--ease) infinite;color:var(--ember);}
.tr-ring-t{position:absolute;inset:0;display:grid;place-items:center;
  font-family:var(--font-mono);font-size:1.75rem;font-weight:700;
  font-variant-numeric:tabular-nums;color:var(--fg-max);}
.trainer-sm .tr-ring-t{font-size:1.375rem;}
.tr-restlab{font-size:var(--t-xs);color:var(--fg-dim);margin:0 0 .75rem;}
.tr-row{display:flex;gap:.5rem;justify-content:center;flex-wrap:wrap;}

/* всё сделано */
.tr-fin{text-align:center;}
.tr-fin-t{display:flex;align-items:center;justify-content:center;gap:.4375rem;
  margin:.25rem 0 .375rem;font-family:var(--font-display);font-weight:800;
  letter-spacing:var(--tracking-h);color:var(--accent);}
.tr-fin-t svg{width:1.125rem;height:1.125rem;stroke-width:2.6;}
.tr-sum{font-size:var(--t-xs);color:var(--fg-dim);margin:0 0 .875rem;}

.tr-foot{display:flex;align-items:center;justify-content:space-between;
  gap:.75rem;margin-top:.75rem;min-height:1.25rem;}
.tr-undo{display:inline-flex;align-items:center;gap:.375rem;padding:0;border:0;
  background:none;cursor:pointer;font-size:var(--t-xs);color:var(--fg-dim);
  transition:color .2s var(--ease);}
.tr-undo:hover{color:var(--fg-max);}
.tr-undo[hidden]{display:none;}
.tr-undo svg{width:.875rem;height:.875rem;}
.tr-err{font-size:var(--t-xs);color:var(--bad);}
.tr-err[hidden]{display:none;}

/* смена лица — мягкий заход снизу, чтобы переход читался как шаг вперёд */
@keyframes tr-in{from{opacity:0;transform:translateY(6px);}to{opacity:1;transform:none;}}
.tr-face.in{animation:tr-in .3s var(--ease-out);}

/* пока идёт запрос — панель слегка гаснет, кнопки не ловят второй клик */
.trainer.busy{opacity:.6;pointer-events:none;}

/* ── режим занятия ──
   Пока идёт подход или тикает отдых, панель перестаёт быть карточкой в потоке
   и становится тем, на что смотрят с расстояния вытянутой руки: счётчик во весь
   столбец, кнопки под большой палец, поля в собственных лотках. Класс .live
   ставит app.js в face(), поэтому режим живёт ровно столько, сколько идёт
   работа, — в покое тренажёр снова компактный и не распирает страницу. */
.trainer.live{padding:1.375rem 1.25rem 1.25rem;border-color:var(--g-edge-hi);
  box-shadow:0 0 0 1px var(--lime-glow),0 24px 60px -34px rgba(0,0,0,.8);}
.trainer-sm.live{padding:1.25rem 1.125rem 1.125rem;border-radius:var(--r-lg);}
.trainer.live .tr-head{margin-bottom:.75rem;}

/* подход: номер — подпись, время — главный объект на экране */
.trainer.live .tr-now{display:grid;justify-content:center;justify-items:center;
  gap:.25rem;text-align:center;margin-bottom:1.125rem;}
.trainer.live .tr-setno{font-size:var(--t-sm);font-weight:700;
  text-transform:uppercase;letter-spacing:.14em;color:var(--fg-dim);}
.trainer.live .tr-clock{font-size:clamp(3rem,14vw,4.25rem);font-weight:700;
  letter-spacing:-.03em;color:var(--fg-max);}

/* повторы и вес: лоток вокруг пары, чтобы поле и кнопки читались как один орган */
.trainer.live .tr-field{gap:1rem;margin-bottom:.75rem;padding:.5rem .625rem;
  border-radius:var(--r-md);background:var(--g3-bg);}
.trainer.live .tr-lab{font-size:var(--t-sm);font-weight:600;color:var(--fg);}
.trainer.live .tr-step{gap:.5rem;}
.trainer.live .tr-pm{width:3rem;height:3rem;border-radius:var(--r-md);}
.trainer.live .tr-pm svg{width:1.375rem;height:1.375rem;}
.trainer.live .tr-num{width:5rem;height:3rem;font-size:1.25rem;
  border-radius:var(--r-md);}

/* отдых: кольцо во всю ширину панели, цифры видно от пола */
.trainer.live .tr-ring{width:min(15rem,62vw);height:min(15rem,62vw);
  margin:.5rem auto 1rem;}
.trainer.live .tr-ring circle{stroke-width:5;}
.trainer.live .tr-ring-t{font-size:clamp(2.5rem,12vw,3.5rem);letter-spacing:-.03em;}
.trainer.live .tr-restlab{font-size:var(--t-md);color:var(--fg);margin-bottom:1rem;}
.trainer.live .tr-row{gap:.625rem;}

/* главное действие крупнее вспомогательных: «подход выполнен» нащупывается не глядя */
.trainer.live [data-act="done"]{min-height:3.5rem;font-size:1.0625rem;}
.trainer.live .tr-row .btn,
.trainer.live [data-act="abort"]{min-height:3rem;padding-inline:1.25rem;
  font-size:var(--t-sm);}
.trainer.live [data-act="done"] svg,
.trainer.live .tr-row .btn svg{width:1.125rem;height:1.125rem;}
.trainer.live .tr-undo{min-height:2.75rem;font-size:var(--t-sm);}
.trainer.live .tr-undo svg{width:1rem;height:1rem;}

@media(min-width:720px){
  /* На широкой панели поля растягивались во всю ширину, и от подписи до
     степпера было полметра пустоты. Режиму занятия хватает колонки: содержимое
     собираем по центру, панель остаётся широкой плитой. */
  .trainer.live .tr-face{max-width:30rem;margin-inline:auto;}
}

@media(prefers-reduced-motion:reduce){
  .tr-ring-fg{transition:none;}
  .tr-ring.soon .tr-ring-t{animation:none;}
}

/* ── лента перехода между упражнениями ──
   Страница упражнения не должна быть тупиком: снизу всегда видно, что было
   до и что будет после, и как вернуться в урок. На узком экране ряд
   схлопывается в столбец — стрелки остаются по краям. */
.ex-nav{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;
  gap:.75rem;margin:0 0 2rem;padding:1rem;border-radius:var(--r-lg);
  background:var(--g1-bg);border:1px solid var(--g-edge);}
.ex-nav-i{display:flex;align-items:center;gap:.625rem;min-width:0;
  color:var(--fg);text-decoration:none;
  transition:color .2s var(--ease),transform .25s var(--ease);}
.ex-nav-i.tr{justify-content:flex-end;text-align:right;}
.ex-nav-i:hover{color:var(--fg-max);}
.ex-nav-i:hover svg{color:var(--accent);}
.ex-nav-i svg{width:1.125rem;height:1.125rem;flex:none;
  transition:transform .25s var(--ease);}
.ex-nav-i:hover .arr{transform:translateX(3px);}
.ex-nav-i:hover svg:first-child:not(.arr){transform:translateX(-3px);}
.ex-nav-i span{display:block;min-width:0;font-size:var(--t-sm);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.ex-nav-i b{display:block;font-weight:600;letter-spacing:var(--tracking-eyebrow);
  text-transform:uppercase;}
.ex-nav-up{flex:none;white-space:nowrap;}
@media(max-width:47.99em){
  .ex-nav{grid-template-columns:1fr 1fr;}
  .ex-nav-up{grid-column:1/-1;order:-1;justify-self:center;}
}

/* ── завершение урока ──
   Панель стоит последней в уроке — после всех упражнений. Это осознанный
   шаг, а не кнопка по пути, поэтому у неё своя плита и крупная цель. */
.ls-finish{display:flex;align-items:center;justify-content:space-between;
  gap:1rem;flex-wrap:wrap;margin:0 0 1.5rem;}
.ls-finish-t{min-width:0;}
@media(max-width:600px){
  .ls-finish{flex-direction:column;align-items:stretch;text-align:center;}
  .ls-finish .row{justify-content:center;}
  .ls-finish .btn{flex:1 1 12rem;justify-content:center;}
}

/* ══════════════════════ КАБИНЕТ: РОЗА ЗОН ══════════════════════
   Десять лепестков вместо радара. У многоугольника вершина одной зоны
   тянет за собой рёбра соседних, и провал читается как общая вмятина;
   лепестки независимы — каждый показывает свою зону и ничего не обещает
   за соседа. Цвет лепестка — уровень, длина — прогресс внутри уровня;
   бледный призрак позади держит шкалу, чтобы пустая зона была видна
   как пустое место, а не как отсутствие элемента. */
.rose-box{max-width:27rem;margin-inline:auto;}
/* Собственные токены: стеклянные --g*-bg — это многослойные background,
   а SVG fill принимает только цвет, и var(--g3-bg) там молча становится
   чёрным. Поэтому у розы свои плоские значения на обе темы. */
.rose{display:block;width:100%;height:auto;overflow:visible;
  --ro-gh:rgba(255,255,255,.028);--ro-gh-on:rgba(255,255,255,.08);
  --ro-core:rgba(255,255,255,.075);
  --ro-hair:rgba(255,255,255,.09);--ro-ring:rgba(255,255,255,.15);}
:root.light .rose{--ro-gh:rgba(19,19,17,.03);--ro-gh-on:rgba(19,19,17,.07);
  --ro-core:rgba(19,19,17,.045);
  --ro-hair:rgba(19,19,17,.11);--ro-ring:rgba(19,19,17,.17);}

/* Кольца — шкала уровней, и без них длина лепестка не значит ничего.
   Пунктир для промежуточных, сплошная линия для пятого: край круга
   должен читаться как рамка, а не как ещё одна отметка. */
.rose .rg{fill:none;stroke:var(--ro-ring);stroke-width:1;
  stroke-dasharray:2 4;opacity:.8;}
.rose .rg-max{stroke-dasharray:none;stroke-width:1.2;opacity:1;}

/* Призрак лепестка держит клик по пустой зоне и больше ничего: с заметной
   заливкой десять серых лепестков читались как наполовину увядший цветок,
   а кольца под ними пропадали. Он проявляется только под курсором. */
.rose .gh{fill:var(--ro-gh);stroke:none;
  transition:fill .25s var(--ease);}
.rose .slot:hover .gh{fill:var(--ro-gh-on);}
.rose .pet{stroke:none;transition:filter .3s var(--ease),opacity .3s var(--ease);}
.rose .sh{pointer-events:none;}

.rose .lv0 .pet{fill:rgba(200,245,66,.42);}
/* На светлом фоне полупрозрачный лайм выцветает до бумаги, и первый
   подход снова не виден — там берём насыщенный тон, а не прозрачность. */
:root.light .rose .lv0 .pet{fill:rgba(168,211,31,.75);}
.rose .lv1 .pet{fill:var(--lime-700);}
.rose .lv2 .pet{fill:var(--lime-600);}
.rose .lv3 .pet{fill:var(--lime-500);}
.rose .lv4 .pet{fill:var(--lime-400);}
.rose .lv5 .pet{fill:var(--lime-300);filter:drop-shadow(0 0 .5rem var(--lime-glow));}

/* Фигурка зоны вместо номера. Цвет держит уровень: пустая зона
   уходит в приглушённый, пройденная светится акцентом. */
.rose .slot{cursor:pointer;}
.rose .slot-i{color:var(--accent);pointer-events:none;}
.rose .off .slot-i{color:var(--fg-dim);}
.rose .slot:hover .slot-i,.rose .slot:focus-visible .slot-i{color:var(--fg-max);}
.rose .slot:focus-visible{outline:none;}
.rose .slot:focus-visible .gh{fill:var(--ro-gh-on);
  stroke:var(--accent);stroke-width:2;}

/* Сердцевина держит средний уровень: одно число, ради которого человек
   и заходит, — стоит в центре круга, а не в подписи сбоку. Подпись под
   ним объясняет, что это уровень, а не подходы и не килограммы. */
.rose .core{fill:var(--ro-core);stroke:var(--ro-hair);stroke-width:1;}
.rose .core-n{fill:var(--fg-max);font-size:17px;font-weight:800;text-anchor:middle;
  dominant-baseline:central;pointer-events:none;}
.rose .core-c{fill:var(--fg-dim);font-size:8px;font-weight:700;text-anchor:middle;
  dominant-baseline:central;pointer-events:none;
  letter-spacing:.04em;text-transform:uppercase;}

/* Наведение на лепесток приглушает остальные: сравнивать удобнее,
   когда лишнее уходит на полтона назад, а не исчезает совсем. */
.rose:hover .slot:not(:hover) .pet{opacity:.34;}

@media (prefers-reduced-motion:no-preference){
  .rose .pet,.rose .sh{transform-box:view-box;transform-origin:180px 180px;
    animation:bloom .72s var(--ease) both;
    animation-delay:calc(var(--d,0) * .045s);}
  .rose .rg{animation:fadein .5s var(--ease) both;}
  .rose .slot-i,.rose .core-n,.rose .core-c{animation:fadein .5s var(--ease) both;
    animation-delay:calc(.42s + var(--d,0) * .045s);}
}
@keyframes bloom{from{transform:scale(.16);opacity:0;}to{transform:scale(1);opacity:1;}}
@keyframes fadein{from{opacity:0;}to{opacity:1;}}

/* Легенда: одна строка объясняет и шаг между кольцами, и цвет лепестка —
   это один и тот же уровень. Пять квадратов вместо текста, потому что
   пять подписей по кругу не влезают ни в один из одиннадцати языков. */
.rose-key{display:flex;align-items:center;justify-content:center;
  flex-wrap:wrap;gap:.5rem .625rem;margin-top:.875rem;}
.rk-t{font-size:var(--t-xs);color:var(--fg-dim);}
.rk-s{display:inline-flex;gap:.25rem;}
.rk-s>i{display:grid;place-items:center;width:1.375rem;height:1.375rem;
  border-radius:var(--r-sm);font-size:.6875rem;font-weight:800;
  font-style:normal;color:var(--ink);}
.rk-s>.lv1{background:var(--lime-700);color:var(--n-0);}
.rk-s>.lv2{background:var(--lime-600);}
.rk-s>.lv3{background:var(--lime-500);}
.rk-s>.lv4{background:var(--lime-400);}
.rk-s>.lv5{background:var(--lime-300);box-shadow:0 0 .5rem var(--lime-glow);}

/* ── сводка цифрами ── */
.me-nums{display:grid;grid-template-columns:repeat(3,1fr);gap:.875rem .5rem;}
.me-nums>div{display:flex;flex-direction:column;gap:.125rem;min-width:0;}
.me-nums b{font-size:1.5rem;line-height:1.1;color:var(--fg-max);}
.me-nums span{font-size:var(--t-xs);color:var(--fg-dim);line-height:1.25;}

.me-weak .zrow-i{flex:none;}

/* ── список зон ── */
.zlist{list-style:none;margin:0;padding:0;display:grid;gap:.5rem;}
@media(min-width:56rem){.zlist{grid-template-columns:1fr 1fr;}}
.zrow{display:flex;align-items:center;gap:.75rem;padding:.75rem .875rem;
  border-radius:var(--r-md);text-decoration:none;color:inherit;}
.zrow-i{flex:none;display:grid;place-items:center;width:2.75rem;height:2.75rem;
  border-radius:var(--r-sm);background:var(--g3-bg);color:var(--fg);}
.zrow-b{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:.25rem;}
.zrow-n{font-weight:700;font-size:var(--t-sm);color:var(--fg-max);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.zrow-h{line-height:1.25;}
.zrow-v{flex:none;text-align:right;display:flex;flex-direction:column;gap:.125rem;}
.zrow-v b{font-size:1.125rem;line-height:1.1;color:var(--fg-max);}
.zbar{display:block;height:.3125rem;border-radius:var(--r-pill);
  background:var(--g3-bg);overflow:hidden;}
.zbar>i{display:block;height:100%;border-radius:inherit;background:var(--accent);
  transition:width .6s var(--ease);}
.zrow.lv0 .zrow-i{color:var(--fg-dim);}
.zrow.lv5 .zbar>i{box-shadow:0 0 .5rem var(--lime-glow);}

/* ── последние дни ── */
.me-days{list-style:none;margin:0;padding:0;display:grid;gap:.5rem;}
.me-days>li{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap;
  border-radius:var(--r-md);}
.me-day-d{flex:none;font-weight:800;font-size:var(--t-sm);color:var(--fg-max);
  font-variant-numeric:tabular-nums;}
.me-day-z{display:flex;gap:.25rem;flex-wrap:wrap;color:var(--fg-dim);}
.me-day-n{margin-left:auto;color:var(--fg-dim);white-space:nowrap;}

/* ── чип профиля в шапке ──
   Срок доступа перестал быть плашкой-уведомлением и стал входом в кабинет:
   кольцо вокруг иконки показывает средний уровень, так что прогресс виден
   с любой страницы, а дата осталась там же, где человек привык её искать. */
.me-chip{display:inline-flex;align-items:center;gap:.5rem;
  padding:.1875rem .75rem .1875rem .1875rem;border-radius:var(--r-pill);
  border:1px solid var(--g-edge);background:var(--g2-bg);
  text-decoration:none;color:inherit;
  transition:border-color .3s var(--ease),background .3s var(--ease),
             transform .3s var(--ease);}
.me-chip:hover{border-color:var(--g-edge-hi);background:var(--g3-bg);
  transform:translateY(-1px);}
.me-chip:active{transform:translateY(0);}
.me-ring{position:relative;flex:none;width:2rem;height:2rem;border-radius:50%;
  display:grid;place-items:center;
  background:conic-gradient(var(--accent) calc(var(--p,0) * 1%),var(--g3-bg) 0);}
.me-ring::after{content:'';position:absolute;inset:.125rem;border-radius:50%;
  background:var(--g1-bg);}
.me-ring svg{position:relative;z-index:1;width:1rem;height:1rem;color:var(--fg-max);}
.me-chip-b{display:flex;flex-direction:column;line-height:1.15;min-width:0;}
.me-chip-t{font-size:.5625rem;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;color:var(--fg-dim);}
.me-chip-d{font-size:var(--t-xs);font-weight:700;color:var(--fg-max);
  font-variant-numeric:tabular-nums;white-space:nowrap;}
@media(max-width:560px){
  .site-head .me-chip{order:4;margin-left:auto;padding:.125rem .5rem .125rem .125rem;}
  .site-head .me-chip .me-ring{width:1.75rem;height:1.75rem;}
  .site-head .me-chip-t{display:none;}
}

/* ══════════════════════ УСТАНОВЛЕННОЕ ПРИЛОЖЕНИЕ ══════════════════════ */
/* Ставится на телефон как приложение. Системной рамки тут нет, поэтому шапку
   и подвал приходится отодвигать самим — иначе выход уезжает под «чёлку»,
   а телеграм-кнопка прячется за домашней полосой. */
html{-webkit-tap-highlight-color:transparent;}
@media (display-mode:standalone),(display-mode:minimal-ui),(display-mode:fullscreen){
  html,body{overscroll-behavior-y:contain;}
  .site-head{padding-top:max(.5rem,env(safe-area-inset-top));}
  .foot{padding-bottom:max(1.5rem,calc(env(safe-area-inset-bottom) + .75rem));}
  main{padding-left:env(safe-area-inset-left);padding-right:env(safe-area-inset-right);}
  /* В приложении нет адресной строки — «назад» остаётся только наша. */
  .skip{display:none;}
}

/* ─────────────────── анкета и вес: карточка тела, график, форма ───────────────────
   Цвет линии берётся из --accent: это плоский цвет, в отличие от --g*-bg, которые
   являются многослойным background и в SVG fill молча дают чёрный. */
.wrap-nar{max-width:44rem;}
.tile-body .who{letter-spacing:.01em;}

.wstat{display:flex;align-items:baseline;gap:.5rem;flex-wrap:wrap;}
.wstat .num{font-size:clamp(2.25rem,7vw,3rem);line-height:1;letter-spacing:-.03em;}
.wunit{font-size:var(--t-md);color:var(--fg-dim);font-weight:600;}
.wdelta{margin-left:auto;font-size:var(--t-xs);color:var(--fg-dim);
  padding:.25rem .5rem;border-radius:var(--r-pill);border:1px solid var(--g-edge);}
.wdelta.down{color:var(--accent);border-color:color-mix(in srgb,var(--accent) 38%,transparent);}
.wdelta.up{color:var(--fg);}

/* Шкала ИМТ: не светофор, а положение на отрезке 15…35. Красить её в «плохо»
   значило бы ставить диагноз по двум числам, чего одна формула не умеет. */
.bmi-bar{position:relative;display:block;height:.375rem;margin-top:.5rem;
  border-radius:var(--r-pill);
  background:linear-gradient(90deg,#6AA9FF 0%,var(--accent) 34%,#FFC46B 62%,var(--ember-500) 100%);
  opacity:.55;}
.bmi-bar i{position:absolute;top:50%;width:.75rem;height:.75rem;margin-left:-.375rem;
  border-radius:50%;background:var(--fg-max);border:2px solid var(--bg);
  transform:translateY(-50%);}

.wform{display:grid;grid-template-columns:1fr 1fr;gap:.625rem;}
.wform .btn{grid-column:1/-1;}
@media (min-width:30rem){.wform{grid-template-columns:minmax(6rem,1fr) auto auto;}
  .wform .btn{grid-column:auto;}}

.wchart{display:block;width:100%;height:auto;--wline:var(--accent);overflow:visible;}
.wl{fill:none;stroke:var(--wline);stroke-width:2.5;vector-effect:non-scaling-stroke;
  stroke-linecap:round;stroke-linejoin:round;}
.wd{fill:var(--bg);stroke:var(--wline);stroke-width:2;vector-effect:non-scaling-stroke;}
.wd.on{fill:var(--wline);}

.wlist{list-style:none;margin:0;padding:0;max-height:13rem;overflow-y:auto;}
.wlist li{display:flex;align-items:center;gap:.5rem;padding:.4375rem 0;
  border-top:1px solid var(--g-edge);}
.wlist li:first-child{border-top:0;}
.wlist .num{font-size:var(--t-md);margin-left:auto;}
.wlist form{display:flex;}

.pform{display:block;}
.fld{display:block;margin-bottom:1rem;border:0;padding:0;}
.fld-l{display:block;margin-bottom:.4375rem;font-size:var(--t-xs);font-weight:600;
  letter-spacing:.06em;text-transform:uppercase;color:var(--fg-dim);}
.frow{display:grid;grid-template-columns:1fr;gap:0 .75rem;}
@media (min-width:30rem){.frow{grid-template-columns:1fr 1fr;}}
.check-row{display:flex;margin-bottom:.75rem;}
.rule{height:1px;border:0;margin:1.25rem 0;background:var(--g-edge);}

/* Сегменты вместо выпадающего списка: два-пять вариантов видно целиком,
   и выбор — одно касание, а не три. */
.seg{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:.375rem;
  padding:.25rem;border-radius:var(--r-md);background:var(--g3-bg);
  border:1px solid var(--g-edge);}
.seg-wrap{grid-auto-flow:row;grid-template-columns:repeat(auto-fit,minmax(6rem,1fr));}
.seg-i{position:relative;display:block;}
.seg-i input{position:absolute;inset:0;opacity:0;cursor:pointer;}
.seg-i span{display:block;padding:.5rem .375rem;border-radius:calc(var(--r-md) - .25rem);
  text-align:center;font-size:var(--t-sm);font-weight:600;color:var(--fg-dim);
  transition:background .25s var(--ease),color .25s var(--ease);}
.seg-i input:checked + span{background:var(--accent);color:var(--accent-ink);}
.seg-i input:focus-visible + span{outline:2px solid var(--accent);outline-offset:2px;}
@media (hover:hover){.seg-i input:not(:checked):hover + span{color:var(--fg-max);}}

/* ─── активность с гаджетов ─── */
/* Четырнадцать дней шагов. Колонка остаётся на месте и в пустой день:
   пропуск — такой же ответ, как рекорд, и ряд не должен схлопываться. */
.hbars{display:flex;align-items:flex-end;gap:.25rem;height:4.75rem;}
.hb{flex:1 1 0;height:100%;display:flex;align-items:flex-end;
  border-radius:var(--r-sm);background:rgba(255,255,255,.045);overflow:hidden;}
:root.light .hb{background:rgba(19,19,17,.055);}
.hb>i{display:block;width:100%;min-height:.125rem;border-radius:inherit;
  background:linear-gradient(180deg,var(--lime-400),var(--lime-600));}
/* Сегодняшний день ярче: он ещё не закончился, и его столбик
   читается иначе, чем закрытые дни. */
.hb.is-now>i{background:linear-gradient(180deg,var(--lime-300),var(--lime-500));
  box-shadow:0 0 .5rem var(--lime-glow);}
@media (prefers-reduced-motion:no-preference){
  .hb>i{animation:hgrow .5s var(--ease) both;transform-origin:bottom;}
}
@keyframes hgrow{from{transform:scaleY(0);}to{transform:scaleY(1);}}

/* ─── полоса связки с телеграмом ─── */

/* Полоса, а не карточка: это не раздел кабинета, а одно действие, и по весу
   оно должно стоять между шапкой и содержимым, не притворяясь блоком. */
.tgb{display:flex;align-items:center;gap:.875rem;flex-wrap:wrap;}
.tgb-i{flex:0 0 auto;display:grid;place-items:center;width:2.5rem;height:2.5rem;
  border-radius:var(--r-pill);background:rgba(214,255,99,.12);
  border:1px solid rgba(214,255,99,.22);color:var(--accent);}
.tgb-i svg{width:1.125rem;height:1.125rem;}
.tgb-t{flex:1 1 14rem;display:flex;flex-direction:column;gap:.125rem;min-width:0;}
.tgb .btn{flex:0 0 auto;}
:root.light .tgb-i{background:rgba(168,211,31,.14);border-color:rgba(168,211,31,.3);}

/* На телефоне кнопка переезжает на свою строку. Оставить её под иконкой —
   значит оторвать от фразы, которую она выполняет: сдвигаем в колонку текста,
   а иконку поднимаем к заголовку, чтобы не висела посреди абзаца. */
@media (max-width:34rem){
  .tgb{align-items:flex-start;}
  .tgb .btn{margin-left:3.375rem;}
}

/* Пока связи нет, полоса должна просить о себе — но шёпотом: медленное
   дыхание рамки заметно краем глаза и не мешает читать страницу. */
@media (prefers-reduced-motion:no-preference){
  .tgb:not(.tgb-on){animation:tgpulse 4.5s var(--ease) infinite;}
}
@keyframes tgpulse{
  0%,100%{box-shadow:0 0 0 0 rgba(214,255,99,0);}
  50%    {box-shadow:0 0 0 .1875rem rgba(214,255,99,.09);}
}

/* ─── подключение гаджетов ─── */

/* Согласие без анкеты — не запрет, а развилка, поэтому иконка слева и
   кнопка рядом с текстом, а не полоса-предупреждение на всю карточку. */
.lk-note{display:flex;gap:.875rem;align-items:flex-start;}
.lk-note > svg{flex:0 0 auto;width:1.5rem;height:1.5rem;color:var(--accent);}

/* Ключ показывается один раз, и его почти всегда копируют, а не читают.
   Поэтому кнопка стоит вплотную к строке, а сама строка умеет переноситься:
   на узком экране 32 символа в одну строку не влезают, и обрезать их
   многоточием нельзя — это секрет, а не подпись. */
.keybox{display:flex;flex-wrap:wrap;gap:.5rem;align-items:center;}
.keyval{flex:1 1 14rem;min-width:0;padding:.5rem .625rem;border-radius:var(--r-sm);
  background:var(--g3-bg);border:1px solid var(--g-edge);
  font-family:var(--font-mono);font-size:var(--t-sm);font-weight:600;
  letter-spacing:.02em;word-break:break-all;-webkit-user-select:all;user-select:all;}
.keyval-sm{display:inline-block;flex:0 1 auto;padding:.1875rem .375rem;
  font-size:var(--t-xs);font-weight:500;letter-spacing:0;}
/* «Скопировано» держится 1.6 с и уходит само: подтверждение нужно ровно на
   то время, пока человек ещё смотрит на кнопку. */
.btn.is-done{background:var(--accent);color:var(--accent-ink);border-color:transparent;}

.lk-grid{display:grid;grid-template-columns:1fr;gap:1rem;}
@media (min-width:52rem){.lk-grid{grid-template-columns:1fr 1fr;}}
/* Карточки платформ выравниваются по низу: у iPhone пять шагов, у Android
   одна кнопка, и без этого кнопка висела бы в воздухе посередине. */
.lk-card{display:flex;flex-direction:column;}
.lk-card > :last-child{margin-top:auto;}

.lk-steps{margin:0;padding:0 0 0 1.375rem;list-style:decimal;}
.lk-steps li{margin-bottom:.5rem;font-size:var(--t-sm);color:var(--fg-dim);line-height:1.55;}
.lk-steps li:last-child{margin-bottom:0;}
.lk-steps::marker,.lk-steps li::marker{color:var(--accent);font-weight:700;}

.lk-api{margin:0;display:grid;grid-template-columns:1fr;gap:.25rem .875rem;}
.lk-api dt{font-size:var(--t-xs);font-weight:600;letter-spacing:.06em;
  text-transform:uppercase;color:var(--fg-dim);}
.lk-api dd{margin:0 0 .75rem;min-width:0;}
.lk-api dd:last-child{margin-bottom:0;}
@media (min-width:34rem){.lk-api{grid-template-columns:auto 1fr;align-items:baseline;}
  .lk-api dt{padding-top:.25rem;}}
