/* ============================================================
   ШРИФТЫ — свои, а не с Google.
   Раньше здесь стоял @import с fonts.googleapis.com, и это было плохо сразу
   тремя способами. Первый хуже остальных: @import БЛОКИРУЕТ отрисовку, пока
   запрос не завершится, — если чужой домен отвечает медленно или не отвечает
   (а продукт рассчитан на Россию без VPN), ребёнок смотрит на пустую
   страницу весь таймаут и думает, что сайт сломался. Второй: service worker
   намеренно не кэширует чужие адреса, поэтому офлайн шрифты не приезжали
   вовсе и офлайн выглядел иначе, чем онлайн. Третий: однофайловая сборка
   обещает в шапке «ничего не грузится извне», а на деле грузила.

   Взяты переменные начертания, только latin и cyrillic (без греческого,
   вьетнамского и прочего) — пять файлов, 134 КБ на всё. Лицензия OFL это
   разрешает. Файлы обязаны лежать в списке SHELL в sw.js, иначе офлайн
   снова останется без шрифтов; за списком следит тест.

   У Fredoka кириллицы нет вовсе — это не потеря: русские заголовки и раньше
   рисовались следующим в стопке Inter, ровно так же они рисуются и сейчас.
   ============================================================ */
@font-face{font-family:'Fredoka';font-style:normal;font-weight:500 700;font-display:swap;
  src:url('../fonts/fredoka-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Inter';font-style:normal;font-weight:400 700;font-display:swap;
  src:url('../fonts/inter-cyrillic.woff2') format('woff2');
  unicode-range:U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116}
@font-face{font-family:'Inter';font-style:normal;font-weight:400 700;font-display:swap;
  src:url('../fonts/inter-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:400 700;font-display:swap;
  src:url('../fonts/jetbrains-mono-cyrillic.woff2') format('woff2');
  unicode-range:U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:400 700;font-display:swap;
  src:url('../fonts/jetbrains-mono-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}


/* ============================================================
   ЦВЕТА: две темы, и обе описаны ОДНИМ набором переменных.
   Раньше тема была одна — тёмная, — и половина цветов стояла прямо в
   правилах («background:#0f1428»). Из-за этого светлой темы не могло
   существовать в принципе: жёсткий цвет не переопределить.
   Теперь любой цвет, который меняется между темами, живёт здесь.

   По умолчанию тема СВЕТЛАЯ. Тёмный фон читается тяжело при дневном свете
   и на плохих экранах, а тренажёр открывают чаще днём. Тому, кто любит
   тёмную, она в один клик: «?» наверху → «Оформление».
   Выбор темы НЕ синхронизируется с сервером: это настройка устройства,
   как и снятые замки, — на телефоне может быть светлая, на ноутбуке тёмная.
   ============================================================ */
:root{
  /* --- светлая (по умолчанию) --- */
  --bg:#f1f4fc; --bg2:#ffffff; --panel:#ffffff; --panel2:#f5f7fe; --sunken:#eef1fa;
  --line:#dde3f1; --line2:#c3cbe4; --ink:#1a1f3d; --soft:#4a5372; --faint:#666e88;
  --acc:#5a41e0; --acc-lt:#7c5cff; --acc2:#00806c; --acc2-lt:#00a68c;
  --gold:#a06f00; --ok:#16814a; --bad:#cf3838; --warn:#a86a08;
  --code:#ffffff;
  --k:#8a2ec0;--s:#227a2e;--n:#c04a12;--c:#767e9b;--f:#1f56c8;--d:#8a5f00;
  --glow1:#e7e9ff; --glow2:#ddf1ee;
  --topbg:rgba(255,255,255,.9);
  --herobg:linear-gradient(150deg,#e9e6ff,#ddf0f3);
  --goalbg:linear-gradient(150deg,#eef0ff,#e5f4f5);
  --bar:#f5f7fd; --bar2:#eef1fa; --res:#f7f9ff; --gut:#f5f7fd; --gutink:#7d85a1;
  --outink:#24304f; --panehead:#f4f6fd;
  --scrim:rgba(24,28,54,.42); --modal:linear-gradient(160deg,#ffffff,#f1f4ff);
  --sunk2:rgba(26,31,61,.06); --onacc:#ffffff; --onacc2:#ffffff;
  --codeink:#4b3ea8; --dot:#ccd3e7; --goldline:#e5d09a; --acc2line:#9ad9cd;
  /* ⚠️ Цвет НЕсобранной звезды — отдельно от --dot (тот для точек-разделителей).
     На --dot пустые звёзды давали контраст 1.4:1, то есть попросту не читались:
     «★☆☆» и «★★★» выглядели как одна звезда против трёх на разном расстоянии, и
     ребёнок не видел, сколько ему осталось. А вся мотивация тут на звёздах. */
  --staroff:#8792b8;
  /* Акцент, когда им набран ТЕКСТ на панели. На светлой теме совпадает с --acc,
     а на тёмной --acc даёт всего 3.7:1 — для мелких надписей мало, поэтому там
     берётся светлый вариант. Рамок и фонов это не касается. */
  --accink:#5a41e0;
  --okbg:rgba(22,129,74,.10); --okline:#a8dcbe; --okink:#0f5f36;
  --badbg:rgba(207,56,56,.08); --badline:#f0b9b9; --badink:#a52626;
  --warnbg:rgba(181,115,10,.10); --warnline:#e8cf9c; --warnink:#8a5806;
  --bugbg:linear-gradient(150deg,#fdeef3,#f7eefb); --bugline:#eec2d1; --bugink:#9c2b4d;
  --claimbg:linear-gradient(150deg,#eef2fd,#f2f0fe); --claimink:#2a4c8f;
  --sh:0 1px 2px rgba(28,35,80,.06),0 14px 32px -22px rgba(28,35,80,.45);
  --shbig:0 24px 60px -20px rgba(28,35,80,.4);
  /* Приглушение «сюда ещё рано» — тоже часть темы. На тёмном фоне оно
     съедает СВЕЧЕНИЕ и строка остаётся читаемой, а на светлом съедает
     КОНТРАСТ: те же 0.42 превращают закрытый урок в еле видимую полоску.
     Поэтому на светлой теме приглушаем заметно слабее. */
  --dim:.62; --dim2:.68;
  --r:16px;
  /* Доска для рисования черепашки — единственный цвет, который НЕ идёт за
     темой, и это нарочно: палитра курса подобрана под тёмный холст.
     `color("white")` и жёлтый на белом фоне просто исчезли бы, а менять
     цвета в уроках ради оформления — портить содержание. Тёмная доска на
     светлой странице читается как доска, а не как чужой кусок.
     Тот же цвет заливает холст `drawTurtle` в js/app.js — он берёт его
     ОТСЮДА, чтобы стиль и рисование не могли разъехаться. */
  --board:#070a16;
}
:root[data-theme="dark"]{
  --bg:#0d1020; --bg2:#141a33; --panel:#181f3d; --panel2:#1f2749; --sunken:#0a0d1c;
  --line:#2a3360; --line2:#3b4680; --ink:#eef1ff; --soft:#a6b0dd; --faint:#7c87bd;
  --acc:#7c5cff; --acc-lt:#9d7bff; --acc2:#00e0b8; --acc2-lt:#00c9a7;
  --gold:#ffc53d; --ok:#3ddc84; --bad:#ff6b6b; --warn:#ffab3d;
  --code:#0a0d1c;
  --k:#c792ea;--s:#c3e88d;--n:#f78c6c;--c:#5f6a9e;--f:#82aaff;--d:#ffcb6b;
  --glow1:#1d2350; --glow2:#17303f;
  --topbg:rgba(13,16,32,.86);
  --herobg:linear-gradient(150deg,#201c4d,#152a44);
  --goalbg:linear-gradient(150deg,#1b2450,#182a45);
  --bar:#0f1428; --bar2:#0c1122; --res:#0b1020; --gut:#080b18; --gutink:#3f4877;
  --outink:#cfe3ff; --panehead:#141a33;
  --scrim:rgba(6,8,18,.82); --modal:linear-gradient(160deg,#1d2350,#16304a);
  --sunk2:rgba(0,0,0,.3); --onacc:#ffffff; --onacc2:#04231e;
  --codeink:#b9c6ff; --dot:#39406e; --goldline:#6b551f; --acc2line:#1c5a52;
  --staroff:#6a74a8;
  --accink:#9d7bff;
  --okbg:rgba(61,220,132,.12); --okline:#1e5c3c; --okink:#8ff0bb;
  --badbg:rgba(255,107,107,.1); --badline:#6b2a2a; --badink:#ffb3b3;
  --warnbg:rgba(255,171,61,.1); --warnline:#6b4d1f; --warnink:#ffd79a;
  --bugbg:linear-gradient(150deg,#3a2030,#2b1c36); --bugline:#6d2f42; --bugink:#ffd0dc;
  --claimbg:linear-gradient(150deg,#1d2b4a,#1a2340); --claimink:#9fd0ff;
  --sh:0 2px 6px rgba(0,0,0,.35),0 18px 40px -22px rgba(0,0,0,.9);
  --shbig:0 30px 80px -20px #000;
  --dim:.42; --dim2:.52;
}

/* ============================================================
   НАБОРЫ ОФОРМЛЕНИЯ: цвет за пройденный мир (пункт 2.5)

   Пройден мир — открылся набор. Меняется только АКЦЕНТ: цвет кнопок,
   свечение фона и шапки. Ни один цвет, отвечающий за смысл (ошибка, успех,
   предупреждение, подсветка кода), набором не трогается — иначе оформление
   начало бы врать про содержание.

   ⚠️ Каждый набор описан ДВАЖДЫ: для светлой темы и отдельно для тёмной.
   Причина не в красоте, а в порядке правил: у `:root[data-skin=...]` и у
   `:root[data-theme="dark"]` одинаковый вес, и набор, стоящий ниже, молча
   перекрасил бы тёмную тему в светлые цвета. Пара `[data-theme][data-skin]`
   весит больше и выигрывает всегда, где бы ни стояла.

   ⚠️ Цвет --acc обязан держать белый текст: на нём стоят кнопки и вкладки.
   Все значения ниже дают на белом не меньше 4,9:1 (проверено расчётом).
   ============================================================ */
:root[data-skin="rostok"]{
  --acc:#17714a; --acc-lt:#1f9a63; --accink:#166b42;
  --glow1:#e0f5e9; --glow2:#ddf1ee;
  --herobg:linear-gradient(150deg,#e2f6ea,#ddf0f3);
  --goalbg:linear-gradient(150deg,#e9f8ee,#e5f4f5);
}
:root[data-theme="dark"][data-skin="rostok"]{
  --acc:#1b7f57; --acc-lt:#28a06d; --accink:#7ce0a6;
  --glow1:#12301f; --glow2:#17303f;
  --herobg:linear-gradient(150deg,#123526,#152a44);
  --goalbg:linear-gradient(150deg,#123023,#182a45);
}
:root[data-skin="dannye"]{
  --acc:#1a52b8; --acc-lt:#2f74e0; --accink:#1a52b8;
  --glow1:#e2ecff; --glow2:#ddf1ee;
  --herobg:linear-gradient(150deg,#e4ecff,#ddf0f3);
  --goalbg:linear-gradient(150deg,#eaf0ff,#e5f4f5);
}
:root[data-theme="dark"][data-skin="dannye"]{
  --acc:#2160c8; --acc-lt:#4a86ee; --accink:#8fbaff;
  --glow1:#152449; --glow2:#17303f;
  --herobg:linear-gradient(150deg,#152a52,#152a44);
  --goalbg:linear-gradient(150deg,#16264a,#182a45);
}
:root[data-skin="svoi"]{
  --acc:#8f5410; --acc-lt:#b8781f; --accink:#8a5000;
  --glow1:#fbeedd; --glow2:#ddf1ee;
  --herobg:linear-gradient(150deg,#fbeedd,#ddf0f3);
  --goalbg:linear-gradient(150deg,#fcf1e3,#e5f4f5);
}
:root[data-theme="dark"][data-skin="svoi"]{
  --acc:#9a5a08; --acc-lt:#c07d1c; --accink:#ffcb6b;
  --glow1:#33230d; --glow2:#17303f;
  --herobg:linear-gradient(150deg,#3a2810,#152a44);
  --goalbg:linear-gradient(150deg,#33230f,#182a45);
}
:root[data-skin="real"]{
  --acc:#20607f; --acc-lt:#2f87ad; --accink:#1f5e78;
  --glow1:#e0f0f7; --glow2:#ddf1ee;
  --herobg:linear-gradient(150deg,#e2f2f9,#ddf0f3);
  --goalbg:linear-gradient(150deg,#e9f4fa,#e5f4f5);
}
:root[data-theme="dark"][data-skin="real"]{
  --acc:#1f6b86; --acc-lt:#3b95b4; --accink:#8fd4f0;
  --glow1:#122b39; --glow2:#17303f;
  --herobg:linear-gradient(150deg,#123141,#152a44);
  --goalbg:linear-gradient(150deg,#122b3a,#182a45);
}
:root[data-skin="pro"]{
  --acc:#a82a67; --acc-lt:#cc4a8c; --accink:#9c1f52;
  --glow1:#fbe6f0; --glow2:#ddf1ee;
  --herobg:linear-gradient(150deg,#fbe7f1,#ddf0f3);
  --goalbg:linear-gradient(150deg,#fcecf4,#e5f4f5);
}
:root[data-theme="dark"][data-skin="pro"]{
  --acc:#b02a63; --acc-lt:#d1508b; --accink:#ff9ec4;
  --glow1:#361026; --glow2:#17303f;
  --herobg:linear-gradient(150deg,#3a1329,#152a44);
  --goalbg:linear-gradient(150deg,#331025,#182a45);
}
/* Плитка выбора набора: тот же ряд, что у темы, плюс закрытые с подписью,
   ЧЕМ они открываются. Закрытая плитка нарочно не спрятана: «за что дают»
   должно быть видно до того, как дали. */
.skinpick{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.skinpick button{display:flex;flex-direction:column;align-items:flex-start;gap:2px;
  min-width:150px;padding:9px 12px;border-radius:12px;border:1px solid var(--line);
  background:var(--panel2);color:var(--ink);font-size:13.5px;cursor:pointer;text-align:left}
.skinpick button .sname{font-weight:700}
.skinpick button .swhen{font-size:11.5px;color:var(--faint)}
.skinpick button.on{border-color:var(--acc);box-shadow:inset 0 0 0 1px var(--acc)}
.skinpick button[disabled]{opacity:.55;cursor:default}
*{box-sizing:border-box}
body{
  margin:0;
  background:
    radial-gradient(1200px 600px at 15% -10%, var(--glow1) 0%, transparent 60%),
    radial-gradient(900px 500px at 90% 0%, var(--glow2) 0%, transparent 55%),
    var(--bg);
  color:var(--ink);font-family:'Inter',system-ui,sans-serif;font-size:16px;line-height:1.6;
  -webkit-font-smoothing:antialiased;overflow-x:hidden;min-height:100vh;
}
code,pre,.mono,textarea{font-family:'JetBrains Mono',ui-monospace,Menlo,Consolas,monospace}
h1,h2,h3{font-family:'Fredoka','Inter',sans-serif;letter-spacing:.005em}
button{font-family:inherit}

/* ---------- шапка ---------- */
.top{position:sticky;top:0;z-index:60;background:var(--topbg);backdrop-filter:blur(14px);border-bottom:1px solid var(--line)}
.top-in{max-width:1080px;margin:0 auto;padding:10px 18px;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
/* Устройство взрослого: прячем всю детскую навигацию в шапке — вкладки уроков,
   звёзды, опыт, «Сегодня», «Повторить», шпаргалку, профиль. Остаётся логотип,
   «?» и (если есть) кнопка «назад». Кабинет не должен выглядеть детским. */
.adminui .tabs,.adminui .xpbox,.adminui .starcount,.adminui #btn-today,
.adminui #btn-again,.adminui #btn-sheet,.adminui #btn-who,.adminui #btn-focus{display:none !important}
.adminui .logo{margin-right:auto}
/* Панель ограничена 1080px и на широком экране НЕ становится шире, поэтому
   влезать в одну строку она обязана всегда — иначе вторая строка съедает
   у урока целый сантиметр экрана. Число опыта из панели убрано: ранг и
   полоска говорят то же самое, а точная цифра висит подсказкой на ранге,
   лежит в профиле и в панели репетитора. Полоска уходит на телефоне. */
#xptext{display:none}

/* Панель обязана влезать в ОДНУ строку при ЛЮБОМ прогрессе, и раньше она
   влезала только пока цифры маленькие. Замер: с рангом «Гуру» и счётчиком
   «★ 300 · 100/100» ей нужно 1061px из 1080 доступных — то есть у пройденного
   курса «?» уезжал на вторую строку, а вторая строка съедает у урока
   сантиметр экрана. Причём заметно это становилось ровно у того ребёнка,
   который дошёл до конца.

   Чиним двумя вещами: переносить запрещаем совсем, а лишнее убираем
   ступенями. Ступени посчитаны замером ширины каждого куска, а не подобраны
   на глаз, и проверены на 1280 / 1100 / 1000 / 900 / 800 / 700 — везде одна
   строка в 60px и ничего не вылезает. Ниже 640 работает своя мобильная
   раскладка в две строки, она сделана нарочно и её не трогаем. */
@media (min-width:641px){ .top-in{flex-wrap:nowrap} }
@media (max-width:1120px){ .xpbar{display:none} }
@media (max-width:1030px){ .lvlchip{display:none} }
@media (max-width:960px){ .logo b{display:none} }
@media (max-width:870px){ #btn-today .lbl{display:none} }
@media (max-width:780px){ .starcount{font-size:12.5px} .tab{padding:7px 8px} }
@media (max-width:720px){ #btn-focus{display:none} }
.logo{display:flex;align-items:center;gap:9px;cursor:pointer}
.logo .mark{width:30px;height:30px;border-radius:9px;background:linear-gradient(135deg,var(--acc),var(--acc2));display:grid;place-items:center;font-size:16px;flex:none}
.logo b{font-family:'Fredoka','Inter',system-ui,sans-serif;font-size:19px;font-weight:600}
.xpbox{display:flex;align-items:center;gap:9px;font-size:13px;color:var(--soft)}
.lvlchip{background:linear-gradient(135deg,var(--acc),var(--acc-lt));color:var(--onacc);font-weight:700;font-size:12px;padding:3px 10px;border-radius:99px;white-space:nowrap}
.xpbar{width:110px;height:8px;border-radius:99px;background:var(--sunken);border:1px solid var(--line);overflow:hidden}
.xpbar i{display:block;height:100%;width:0;background:linear-gradient(90deg,var(--acc2),var(--acc));transition:width .6s cubic-bezier(.2,.8,.3,1)}
.starcount{color:var(--gold);font-weight:700;font-size:13.5px;white-space:nowrap}
.tbtn{border:1px solid var(--line2);background:var(--panel);color:var(--soft);border-radius:10px;padding:7px 12px;font-size:13px;font-weight:600;cursor:pointer;transition:.15s;white-space:nowrap}
.tbtn:hover{color:var(--ink);border-color:var(--acc);background:var(--panel2)}
.tbtn.on{background:var(--acc);color:var(--onacc);border-color:transparent}

/* ---------- полоска «что дальше» на первом уроке ---------- */
.howbar{display:flex;flex-wrap:wrap;align-items:center;gap:6px 16px;margin:0 0 -4px;
  padding:10px 15px;border:1px dashed var(--line2);border-radius:12px;
  background:rgba(0,224,184,.06);font-size:13px;color:var(--soft)}
.howbar>b{color:var(--acc2)}
.howbar span b{color:var(--ink)}

/* ---------- Главное: блок «Сейчас» и карточки разделов ---------- */
.hero.now .nowkicker{font-size:11.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--acc2);font-weight:700;margin-bottom:6px}
.hero.now h1{font-size:30px}
.nowhints{display:flex;flex-wrap:wrap;gap:14px;margin-top:14px;font-size:12.5px;color:var(--faint)}
.howto{margin-top:18px;border:1px solid var(--line);border-radius:var(--r);background:var(--panel);padding:18px 20px}
.howto h3{margin:0 0 10px;font-size:17px}
.howto ol{margin:0;padding-left:20px;color:var(--soft);font-size:14.5px}
.howto li{margin-bottom:6px}
.howto .dim{margin:10px 0 0;font-size:13px}
.hubgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:12px}
.hubcard{display:flex;flex-direction:column;gap:4px;text-align:left;cursor:pointer;color:inherit;
  border:1px solid var(--line);border-radius:16px;background:var(--panel);padding:15px 16px;transition:.15s}
.hubcard:hover{border-color:var(--acc);transform:translateY(-2px);background:var(--panel2)}
.hubcard.more{border-style:dashed;background:transparent}
.hubem{font-size:26px;line-height:1.1}
.hubcard b{font-size:15.5px}
.hubwhy{font-size:13px;color:var(--soft);line-height:1.45}
.hubstat{font-size:11.5px;color:var(--faint);margin-top:2px}

/* ---------- экран «Тренировки» ---------- */
.trainlist{display:flex;flex-direction:column;gap:12px}
.traincard{display:flex;align-items:flex-start;gap:14px;border:1px solid var(--line);
  border-radius:var(--r);background:var(--panel);padding:16px 18px}
.traincard .trainbody{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}
.traincard b{font-size:17px}
.traincard p{margin:0;color:var(--soft);font-size:14px}
.trainwhen{font-size:12.5px;color:var(--acc2)}
.traincard .bigbtn{flex:none;align-self:center}
@media (max-width:620px){
  .traincard{flex-wrap:wrap}
  .traincard .bigbtn{width:100%}
}

/* ---------- вкладки: три раздела верхнего уровня ---------- */
/* Панель раньше была плоским списком из одиннадцати кнопок, и по ней нельзя
   было понять, что уроки — главное, а игры и визуализатор — вокруг. Три
   вкладки задают порядок: учиться → тренироваться → своё. */
/* Распорка стоит на вкладках: слева «куда идти», справа прогресс и
   инструменты. Раньше её держал логотип, и последняя кнопка панели
   уезжала на вторую строку даже на широком экране. */
.tabs{display:flex;gap:3px;padding:3px;margin-right:auto;
  border:1px solid var(--line);border-radius:12px;background:var(--sunken)}
/* Отступы у вкладок посчитаны, а не подобраны на глаз: панель шире 1044px
   переносится на вторую строку, а вторая строка панели съедает у урока
   целый сантиметр экрана. */
.tab{border:0;background:transparent;color:var(--soft);border-radius:9px;padding:7px 11px;
  font-size:13.5px;font-weight:600;cursor:pointer;transition:.15s;white-space:nowrap}
.tab:hover{color:var(--ink)}
.tab.on{background:var(--acc);color:var(--onacc);box-shadow:0 6px 16px -8px rgba(124,92,255,.9)}
@media (max-width:640px){
  /* На телефоне панель складывается в ДВЕ строки: сверху значок, звёзды и
     инструменты, снизу вкладки во всю ширину. Ради этого убираем то, без чего
     на маленьком экране можно жить: слово «Фионика» рядом со значком
     (значок и так ведёт на главную), название ранга (полоски опыта тут тоже
     нет) и «фокус» — он про то, чтобы спрятать лишнее на большом экране. */
  .tab{flex:1;padding:8px 4px;font-size:12.5px}
  .tabs{width:100%;order:9;margin-right:0}
  .logo{margin-right:auto}
  .logo b{display:none}
  .lvlchip{display:none}
  .starsmall{display:none}
  #btn-focus{display:none}
}

.wrap{max-width:1080px;margin:0 auto;padding:26px 18px 90px}

/* ---------- герой и секции ---------- */
.hero{background:var(--herobg);border:1px solid var(--line);border-radius:22px;padding:28px 30px;box-shadow:var(--sh)}
.hero h1{margin:0 0 8px;font-size:34px;line-height:1.12}
.hero p{margin:0;color:var(--soft)}
.hero .row{display:flex;gap:10px;margin-top:18px;flex-wrap:wrap}
.bigbtn{border:0;border-radius:13px;padding:12px 22px;font-size:15px;font-weight:700;cursor:pointer;
  background:linear-gradient(135deg,var(--acc),var(--acc-lt));color:var(--onacc);box-shadow:0 8px 22px -8px rgba(124,92,255,.55);transition:.15s}
.bigbtn:hover{transform:translateY(-2px)}
.bigbtn.ghost{background:transparent;border:1px solid var(--line2);color:var(--soft);box-shadow:none}
/* ⚠️ Ссылка, оформленная кнопкой. Дорога НАРУЖУ (на витрину) делается именно
   ссылкой, а не кнопкой: человек вправе открыть её в новой вкладке и увидеть
   адрес. Но у <button> текст центрируется сам, а у <a> — нет, и без этих двух
   строк надпись прижимается влево и подчёркивается. */
a.bigbtn{text-align:center;text-decoration:none}
.bigbtn.ghost:hover{color:var(--ink);border-color:var(--acc)}
.sect{margin:34px 0 14px;display:flex;align-items:center;gap:12px}
.sect h2{margin:0;font-size:20px}
.sect .line{flex:1;height:1px;background:var(--line)}
.sect .cnt{font-size:13px;color:var(--faint);white-space:nowrap}

/* ---------- миры ---------- */
.worlds{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:14px}
.world{
  background:linear-gradient(160deg,var(--panel),var(--panel2));border:1px solid var(--line);
  border-radius:var(--r);padding:18px 20px;cursor:pointer;transition:.18s;text-align:left;
  color:inherit;font:inherit;box-shadow:var(--sh);
}
.world:hover{transform:translateY(-3px);border-color:var(--acc);box-shadow:0 10px 34px -12px rgba(124,92,255,.6)}
.world.soon{opacity:.62}
.wtop{display:flex;align-items:flex-start;gap:12px}
.wicon{font-size:26px;line-height:1;flex:none;margin-top:2px}
.widx{font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--faint);font-weight:700}
.world h3{margin:3px 0 0;font-size:19px}
.wstat{margin-left:auto;font-size:12px;color:var(--acc2);white-space:nowrap;font-weight:600}
.world p{margin:10px 0 12px;font-size:13.5px;color:var(--soft);line-height:1.5}
.wbar{height:6px;border-radius:99px;background:var(--sunken);border:1px solid var(--line);overflow:hidden}
.wbar i{display:block;height:100%;background:linear-gradient(90deg,var(--acc2),var(--acc));transition:width .5s}
.wfoot{display:flex;justify-content:space-between;align-items:center;margin-top:11px;font-size:12px;color:var(--faint);gap:8px}

.tag{font-size:11px;padding:3px 9px;border-radius:99px;background:var(--sunken);border:1px solid var(--line);color:var(--faint);white-space:nowrap}
.tag.draw{color:var(--acc2);border-color:var(--acc2line)}
.tag.pro{color:var(--gold);border-color:var(--goldline)}

/* ---------- список уроков ---------- */
.lessons{display:flex;flex-direction:column;gap:7px;margin-top:6px}
.lesson{
  display:flex;align-items:center;gap:13px;width:100%;text-align:left;font:inherit;color:inherit;
  background:var(--panel);border:1px solid var(--line);border-radius:13px;padding:11px 15px;
  cursor:pointer;transition:.15s;
}
.lesson:hover{border-color:var(--acc);transform:translateX(3px)}
.lesson.locked,.lesson.soon{opacity:var(--dim);cursor:not-allowed}
.lesson.locked:hover,.lesson.soon:hover{transform:none;border-color:var(--line)}
.lnum{flex:none;width:30px;height:30px;border-radius:9px;background:var(--sunken);border:1px solid var(--line);
  display:grid;place-items:center;font-size:12px;font-weight:700;color:var(--faint)}
.lesson:not(.locked):not(.soon) .lnum{color:var(--acc2);border-color:var(--acc2line)}
.lbody{flex:1;min-width:0}
.lbody b{display:block;font-size:15px;font-weight:600;line-height:1.3}
.lbody span{font-size:12.5px;color:var(--faint)}
.lright{flex:none}
.stars{font-size:13px;letter-spacing:1.5px;color:var(--staroff)}
.stars b{color:var(--gold);font-weight:400}
.soontag{font-size:11px;color:var(--faint);border:1px solid var(--line);border-radius:99px;padding:2px 9px}
.bosstag{display:inline-block;font-size:10px;font-family:'Inter',system-ui,sans-serif;letter-spacing:.08em;text-transform:uppercase;
  color:var(--gold);border:1px solid var(--goldline);border-radius:99px;padding:1px 7px;vertical-align:middle;margin-left:6px}

/* ---------- достижения ---------- */
.badges{display:flex;flex-wrap:wrap;gap:10px}
.badge{display:flex;align-items:center;gap:9px;background:var(--panel);border:1px solid var(--line);border-radius:13px;padding:9px 13px;font-size:13px;opacity:var(--dim);transition:.2s}
.badge.got{opacity:1;border-color:var(--gold);box-shadow:0 0 0 1px rgba(255,197,61,.25),0 8px 20px -12px rgba(255,197,61,.6)}
.badge .em{font-size:19px}
.badge b{display:block;font-size:13px}
.badge span span{color:var(--faint);font-size:11.5px}

/* ---------- урок ---------- */
.crumbs{font-size:12.5px;color:var(--faint);margin-bottom:10px}
.crumbs span{cursor:pointer}
.crumbs span:hover{color:var(--acc2)}
/* Дорога назад живёт в ВЕРХНЕЙ ПАНЕЛИ, одна на все экраны (см. backTarget в
   js/app.js). Внизу страницы такая кнопка тоже есть, но там она за экраном
   ровно в тот момент, когда человек сидит в редакторе или дочитал длинный
   экран до конца. */
/* ⚠️ Класс свой, не .tbtn: в правило «три вкладки и пять инструментов» эта
   кнопка не входит. Инструменты — это «что ещё можно сделать», а это дорога
   назад, и стоит она слева от всего остального. */
.navback{border:1px solid var(--line2);background:var(--panel);color:var(--ink);
  border-radius:10px;padding:7px 12px;font:inherit;font-size:13px;font-weight:700;
  cursor:pointer;transition:.15s;white-space:nowrap}
.navback:hover{border-color:var(--acc);background:var(--panel2)}
.navback[hidden]{display:none}
/* На узком экране от кнопки остаётся стрелка: панель обязана уложиться в две
   строки, а стрелка «назад» понятна и без подписи. */
@media (max-width:720px){ .navback .lbl{display:none} }
.lvlhead{display:flex;align-items:flex-start;gap:14px;flex-wrap:wrap;margin-bottom:6px}
.lvlhead .idx{font-size:11.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--acc2);font-weight:700}
/* Имя ребёнок вводит какое угодно, и длинное слитное имя срезалось правым
   краем — переносим, как уже сделано на сертификате. */
.lvlhead h1{margin:3px 0 0;font-size:29px;line-height:1.15;overflow-wrap:anywhere}
.lvlhead .right{margin-left:auto;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
/* ⚠️⚠️ ПРАВИЛО ПОЛНОЙ ШИРИНЫ — здесь его исток, см. разбор у .secthead.
   У лида НЕТ max-width: он занимает всю ширину своего блока, а ширину блока
   держит .wrap (1080 px). Стояло 66ch — и лид обрывался на 645 при доступных
   1044, ровно то, на что фаундер жаловался словами «опять текст режется».
   Строка кажется длинной — сокращай ТЕКСТ, а не колонку. */
.lede{color:var(--soft);margin:8px 0 22px;font-size:16px}

.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);padding:18px 20px;margin-bottom:14px;box-shadow:var(--sh)}
.card h3{margin:0 0 8px;font-size:17px}
/* ⚠️ БЕЗ потолка ширины, и это жёсткое правило (docs § 14): в одной карточке
   плашки и кнопки занимают всю её ширину, и абзац, обрезанный на 70 знаках
   рядом с ними, читается как «сверху широко, ниже почему-то узко» — жалоба
   фаундера 08.09.2026. Потолок ширины разрешён только отдельно стоящей
   строке (лид), а не тексту среди широких соседей. */
.card p{margin:0 0 10px}
.card p:last-child{margin-bottom:0}
.card p.dim{color:var(--soft);font-size:13.5px;margin-top:10px}
/* pre-wrap, а не обычный перенос: внутри <code> в условиях иногда стоят
   ПРОБЕЛЫ, которые и есть смысл примера — выравнивание таблицы по ширине
   (урок 40) или «лишние пробелы снаружи и внутри» (урок 7). HTML схлопывает
   их в один, и урок показывал ребёнку не то, что печатает программа.
   Переносить строки при этом всё равно можно — за это отвечает «-wrap». */
.card code,.lede code,.goal code,.note code{background:var(--sunken);border:1px solid var(--line);border-radius:5px;padding:1px 6px;font-size:.86em;color:var(--codeink);white-space:pre-wrap;overflow-wrap:anywhere}
.demo pre code,.editorbox code{background:none;border:0;padding:0;font-size:inherit;color:inherit}

.note{border-left:3px solid var(--acc2);background:rgba(0,224,184,.07);padding:13px 16px;border-radius:0 12px 12px 0;margin:0 0 18px;font-size:14.5px;color:var(--soft)}
.note b{display:block;color:var(--ink);margin-bottom:3px;font-size:13px}

.demo{border:1px solid var(--line);border-radius:12px;overflow:hidden;margin:12px 0 4px;background:var(--code)}
.demo pre{margin:0;padding:14px 16px;overflow-x:auto;font-size:13.5px;line-height:1.6}
.demo .bar{display:flex;align-items:center;gap:8px;padding:8px 12px;border-top:1px solid var(--line);background:var(--bar);flex-wrap:wrap}
.demo .bar .hintx{font-size:12px;color:var(--faint);margin-left:auto}
.minibtn{border:1px solid var(--line2);background:var(--panel2);color:var(--ink);border-radius:8px;padding:5px 12px;font-size:12.5px;font-weight:600;cursor:pointer;transition:.15s}
.minibtn:hover{border-color:var(--acc2);color:var(--acc2)}
.demo .res{border-top:1px solid var(--line);background:var(--res);padding:10px 14px;font-size:13px;white-space:pre-wrap;color:var(--acc2);display:none}
.demo .res.show{display:block}
.t-k{color:var(--k)}.t-s{color:var(--s)}.t-n{color:var(--n)}.t-c{color:var(--c);font-style:italic}.t-f{color:var(--f)}.t-d{color:var(--d)}

.goal{background:var(--goalbg);border:1px solid var(--line2);border-radius:var(--r);padding:18px 20px;margin:24px 0 14px}
.goal h3{margin:0 0 8px;font-size:18px}
.goal p{margin:0}
.goal ul{margin:8px 0 0;padding-left:19px;color:var(--soft)}
.goal li{margin-bottom:4px}

/* ---------- студия ---------- */
.studio{display:grid;grid-template-columns:1fr;gap:12px}
.studio.split{grid-template-columns:1fr 340px}
@media (max-width:860px){.studio.split{grid-template-columns:1fr}}

.editorbox{border:1px solid var(--line);border-radius:var(--r);overflow:hidden;background:var(--code);box-shadow:var(--sh)}
.ehead{display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bar);border-bottom:1px solid var(--line);font-size:12px;color:var(--faint)}
.ehead .dot{width:9px;height:9px;border-radius:50%;background:var(--dot)}
.ehead .lbl{margin-left:6px}
/* вкладки файлов: урок из нескольких файлов, как в настоящем проекте */
.ftabs{display:flex;gap:2px;padding:0 8px;background:var(--bar2);border-bottom:1px solid var(--line);overflow-x:auto}
.ftab{border:0;border-bottom:2px solid transparent;background:transparent;color:var(--faint);
  font:600 12px/1 'JetBrains Mono',ui-monospace,monospace;padding:9px 12px;cursor:pointer;white-space:nowrap;transition:.15s}
.ftab:hover{color:var(--soft)}
.ftab.on{color:var(--acc2);border-bottom-color:var(--acc2)}
/* файлы на «диске»: что лежит рядом с программой */
.disklist{display:flex;flex-direction:column;gap:8px}
.diskfile{border:1px solid var(--line);border-radius:10px;background:var(--sunken);padding:8px 10px}
.diskfile b{font:600 12px/1.4 'JetBrains Mono',ui-monospace,monospace;color:var(--acc2)}
.diskfile span{float:right;font-size:11px;color:var(--faint)}
.diskfile pre{margin:6px 0 0;font:12px/1.5 'JetBrains Mono',ui-monospace,monospace;color:var(--soft);
  white-space:pre-wrap;word-break:break-word;max-height:150px;overflow:auto}
.showcode{margin-top:10px;border:1px dashed var(--line);border-radius:12px;background:var(--sunken);padding:10px 12px}
.showcode pre{margin:0;overflow:auto}
.showcode .shownote{display:block;margin-top:8px;font-size:11.5px;color:var(--faint);line-height:1.5}
.stdinbox{width:100%;box-sizing:border-box;resize:vertical;min-height:84px;border:1px solid var(--line);
  border-radius:10px;background:var(--sunken);color:var(--soft);padding:8px 10px;
  font:13px/1.6 'JetBrains Mono',ui-monospace,monospace}
.stdinbox:focus{outline:none;border-color:var(--acc2)}
.stdinhint{margin-top:6px;font-size:11.5px;color:var(--faint);line-height:1.5}

/* игровое поле ввода (раздел «Игры») */
.playbar{display:flex;gap:8px;align-items:center;margin-top:10px;padding:10px 12px;
  border:1px solid var(--acc2);border-radius:12px;background:rgba(0,224,184,.06);flex-wrap:wrap}
.playbar .playq{font:13px/1.4 'JetBrains Mono',ui-monospace,monospace;color:var(--acc2);flex:1 1 140px;min-width:0}
.playbar .playin{flex:1 1 160px;min-width:0;box-sizing:border-box;border:1px solid var(--line);
  border-radius:8px;background:var(--sunken);color:var(--soft);padding:8px 10px;
  font:14px/1.4 'JetBrains Mono',ui-monospace,monospace}
.playbar .playin:focus{outline:none;border-color:var(--acc2)}
.rbtn.play{background:var(--acc2);color:var(--onacc2)}

/* карточки игр */
.gamegrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:14px}
.gamecard{display:flex;flex-direction:column;gap:6px;text-align:left;cursor:pointer;
  border:1px solid var(--line);border-radius:16px;background:var(--panel);padding:16px 16px 18px;
  transition:.15s;color:inherit}
.gamecard:hover{border-color:var(--acc2);transform:translateY(-2px)}
.gamecard .gemoji{font-size:34px;line-height:1}
.gamecard b{font-size:16px}
.gamecard span{font-size:13px;color:var(--soft);line-height:1.5}
.edittag,.gamecard .edittag{font:600 10px/1 sans-serif;color:var(--acc2);border:1px solid var(--acc2);
  border-radius:6px;padding:2px 5px;vertical-align:middle}
.edittag.done{color:var(--acc2);border-color:var(--acc2)}

/* ---------- проект в конце мира ---------- */
.projcard{display:flex;align-items:center;gap:14px;margin-top:18px;padding:16px 18px;
  border:1px solid var(--acc);border-radius:var(--r);box-shadow:var(--sh);
  background:radial-gradient(600px 200px at 15% -60%, rgba(124,92,255,.20) 0%, transparent 60%), var(--panel)}
.projcard.locked{border-color:var(--line);border-style:dashed;background:var(--panel);opacity:.72}
.projcard.done{border-color:var(--ok)}
.pjemoji{font-size:38px;line-height:1;flex:none}
.pjbody{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.pjkicker{font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--accink);font-weight:700}
.pjbody b{font-size:19px;font-family:'Fredoka','Inter',sans-serif}
.pjbody>span:nth-child(3){color:var(--soft);font-size:14px}
.pjnote{color:var(--faint);font-size:12.5px;margin-top:3px}
.projcard .bigbtn{flex:none}
.pstepbar{display:flex;gap:8px;align-items:center;margin:0 0 16px}
.pdot{width:30px;height:30px;border-radius:50%;display:grid;place-items:center;flex:none;
  border:1px solid var(--line2);background:var(--sunken);color:var(--faint);font-size:13px;font-weight:700}
.pdot.done{border-color:var(--ok);color:var(--ok);background:rgba(61,220,132,.10)}
.pdot.now{border-color:var(--acc);color:var(--ink);background:rgba(124,92,255,.18);
  outline:2px solid var(--acc);outline-offset:1px}
@media (max-width:620px){
  .projcard{flex-wrap:wrap}
  .projcard .bigbtn{width:100%}
}

/* ---------- раздел «Сегодня»: дневной стрик и задача дня ---------- */
.tbtn.streak{border-color:var(--warn)}
.tbtn.streak.lit{background:linear-gradient(135deg,var(--warn),#ff7a3d);color:#fff;border-color:transparent}
.streakhero{background:
    radial-gradient(600px 200px at 20% -40%, rgba(255,171,61,.18) 0%, transparent 60%),
    var(--panel);
  border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--sh);
  padding:22px 20px;margin-bottom:16px;text-align:center}
.streakhero .flame{font-size:52px;line-height:1;filter:grayscale(.55) opacity(.7)}
.streakhero .flame.lit{filter:none;animation:flamepulse 2.4s ease-in-out infinite}
@keyframes flamepulse{0%,100%{transform:scale(1)}50%{transform:scale(1.12)}}
.streaknum{font-family:'Fredoka','Inter',sans-serif;font-size:24px;margin-top:6px}
.streaknum b{font-size:30px;color:var(--warn)}
.streaksub{color:var(--soft);font-size:14px;margin-top:4px;max-width:46ch;margin-left:auto;margin-right:auto}
.streakbest{color:var(--faint);font-size:12.5px;margin-top:6px;letter-spacing:.03em}
.weekstrip{display:flex;justify-content:center;gap:8px;margin-top:16px;flex-wrap:wrap}
.wkcell{display:flex;flex-direction:column;align-items:center;gap:4px;width:40px;padding:7px 0;
  border:1px solid var(--line);border-radius:11px;background:var(--sunken)}
.wkcell .wkd{font-size:10.5px;color:var(--faint);text-transform:uppercase;letter-spacing:.04em}
.wkcell .wkdot{font-size:15px;line-height:1;color:var(--faint)}
.wkcell.on{border-color:var(--warn);background:rgba(255,171,61,.12)}
.wkcell.today{outline:2px solid var(--acc);outline-offset:1px}
/* щит для стрика */
.shieldbox{margin-top:14px;padding:10px 14px;border-radius:12px;border:1px dashed var(--line2);
  background:var(--sunken);display:inline-block;max-width:52ch}
.shieldbox.has{border-style:solid;border-color:var(--acc2);background:rgba(0,224,184,.07)}
.shrow{display:flex;align-items:center;justify-content:center;gap:6px;font-size:18px}
.shrow .shoff{filter:grayscale(1) opacity(.3)}
.shnum{font-size:13.5px;color:var(--soft);margin-left:6px}
.shnum b{color:var(--acc2);font-size:16px}
.shsub{color:var(--faint);font-size:12.5px;margin-top:5px;line-height:1.5}
.wkcell.shielded{border-color:var(--acc2);border-style:solid;background:rgba(0,224,184,.10)}
.wkcell.shielded .wkdot{filter:none}
.shieldsaved{margin:10px 0;padding:10px 14px;border-radius:12px;font-size:14px;
  border:1px solid var(--acc2);background:rgba(0,224,184,.10);color:var(--ink)}
.daybanner.shield{background:rgba(0,224,184,.10);border-color:var(--acc2);color:var(--ink)}
.streakline{margin-top:8px;font-size:16px;color:var(--soft)}
.streakline b{color:var(--warn);font-size:20px}
.dailycard{background:var(--panel);border:1px solid var(--line2);border-radius:var(--r);
  box-shadow:var(--sh);padding:18px 20px;margin-bottom:14px}
.dailycard.done{border-color:var(--ok)}
.dctop{display:flex;align-items:center;gap:12px}
.dcemoji{font-size:34px;line-height:1;flex:none}
.dcttl{flex:1;min-width:0}
.dckicker{font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--warn);font-weight:700}
.dcttl b{font-size:18px}
.dcintro{color:var(--soft);font-size:14px;margin:10px 0 12px}
.dcstatus{font-size:13.5px;color:var(--soft);margin-bottom:12px}
.dcstatus.done{color:var(--ok);font-weight:600}
.dailycard .winrow{justify-content:flex-start}
/* расписание занятий */
.tbtn.streak.due{border-color:var(--acc2);color:var(--ink);animation:duepulse 1.8s ease-in-out infinite}
@keyframes duepulse{0%,100%{box-shadow:0 0 0 0 rgba(0,224,184,.0)}50%{box-shadow:0 0 0 4px rgba(0,224,184,.22)}}
.daybanner{border-radius:var(--r);padding:12px 16px;margin-bottom:14px;font-size:14.5px;border:1px solid var(--line)}
.daybanner.due{background:rgba(0,224,184,.12);border-color:var(--acc2);color:var(--ink)}
.daybanner.ok{background:rgba(61,220,132,.10);border-color:var(--ok);color:var(--ink)}
.daybanner.rest{background:var(--panel);color:var(--soft)}
.wkcell.study .wkdot{color:var(--acc2)}
.wkcell.study{border-style:dashed}
.schedcard .wdrow{display:flex;gap:8px;flex-wrap:wrap;margin:4px 0 2px}
.wdchip{border:1px solid var(--line2);background:var(--sunken);color:var(--soft);border-radius:10px;
  padding:8px 0;width:48px;text-align:center;font-weight:700;font-size:13.5px;cursor:pointer;transition:.15s}
.wdchip:hover{border-color:var(--acc);color:var(--ink)}
.wdchip.sel{background:linear-gradient(135deg,var(--acc),#a97bff);color:#fff;border-color:transparent}

/* ---------- регистрация и профиль ---------- */
.tbtn.who{max-width:160px;overflow:hidden;text-overflow:ellipsis}
.reghero{text-align:center;margin:14px 0 18px}
.reghero .regmark{display:inline-grid;place-items:center;width:56px;height:56px;border-radius:16px;
  background:linear-gradient(135deg,var(--acc),var(--acc2));font-size:30px;margin-bottom:8px}
.reghero h1{margin:6px 0 2px;font-size:27px}
.reghero .lede{margin-left:auto;margin-right:auto}
.reglbl{display:block;font-size:13px;color:var(--soft);font-weight:600;margin-bottom:6px}
.reglbl input,.reglbl textarea{display:block;width:100%;margin-top:6px;background:var(--sunken);border:1px solid var(--line2);
  color:var(--ink);border-radius:11px;padding:11px 13px;font-size:16px;font-family:inherit}
.reglbl textarea{resize:vertical;line-height:1.5}
.reglbl input:focus,.reglbl textarea:focus{outline:none;border-color:var(--acc)}
.codebox{display:flex;align-items:center;gap:10px;flex-wrap:wrap;background:var(--sunken);
  border:1px solid var(--line);border-radius:11px;padding:10px 12px}
.codebox code{background:none;border:0;padding:0;color:var(--codeink);font-size:14px;word-break:break-all;flex:1;min-width:0}
.mono{font-family:'JetBrains Mono',monospace;font-size:13px;color:var(--soft);word-break:break-all}

/* раздел «Разминка»: угадай вывод (predict) */
.gamecard .wtag{align-self:flex-start;margin-top:2px;font:600 10.5px/1 'Inter',sans-serif;letter-spacing:.06em;
  text-transform:uppercase;color:var(--faint);border:1px solid var(--line2);border-radius:6px;padding:3px 7px}
.predict{display:flex;flex-direction:column;gap:12px}
.predict .pcode{border:1px solid var(--line);border-radius:var(--r);overflow:hidden;background:var(--code);box-shadow:var(--sh)}
.predict .pcode pre{margin:0;padding:14px 16px;overflow:auto;font-size:14px;line-height:1.62}
.predict .pcode code{background:none;border:0;padding:0;font-size:inherit;color:inherit}
.predict .pans .predin{min-height:120px}
.predict .runbar{border:1px solid var(--line);border-radius:var(--r)}
.predict .msg{margin-top:0}

/* «собери из блоков»: перетаскиваемые строки */
.blocks .ehead{border:1px solid var(--line);border-bottom:0;border-radius:var(--r) var(--r) 0 0}
.blocklist{display:flex;flex-direction:column;gap:8px;border:1px solid var(--line);border-top:0;
  border-radius:0 0 var(--r) var(--r);background:var(--code);padding:12px}
.block{display:flex;align-items:center;gap:10px;background:var(--panel);border:1px solid var(--line2);
  border-radius:10px;padding:6px 10px;cursor:grab;transition:border-color .15s,transform .05s,box-shadow .15s}
.block:hover{border-color:var(--acc)}
.block.dragging{opacity:.55;cursor:grabbing}
.block.over{border-color:var(--acc2);box-shadow:0 0 0 2px rgba(0,224,184,.35)}
.block .bgrip{flex:none;color:var(--faint);font-size:16px;line-height:1;user-select:none;letter-spacing:-1px}
.block .bcode{flex:1;min-width:0;margin:0;overflow-x:auto;white-space:pre;
  font-size:13.5px;line-height:1.5;padding:2px 0}
.block .bcode code{background:none;border:0;padding:0;font-size:inherit;color:inherit}
.block .bmove{flex:none;display:flex;flex-direction:column;gap:2px}
.block .bbtn{border:1px solid var(--line2);background:var(--panel2);color:var(--soft);border-radius:6px;
  width:26px;height:18px;line-height:1;font-size:10px;cursor:pointer;padding:0;transition:.15s}
.block .bbtn:hover{color:var(--ink);border-color:var(--acc2)}

/* ===== визуализатор (машина времени) ===== */
.vizex{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:0 0 14px}
.vizex>span{font-size:12.5px;color:var(--faint)}
.vizbox{display:flex;flex-direction:column;gap:12px}
.vizplayer{display:flex;flex-direction:column;gap:12px}
.vizctl{display:flex;flex-wrap:wrap;gap:8px;align-items:center;padding:10px 12px;border:1px solid var(--line);
  border-radius:var(--r);background:var(--bar)}
.vizslider{flex:1 1 160px;min-width:120px;accent-color:var(--acc)}
.vizpos{font-size:12.5px;color:var(--faint);font-family:'JetBrains Mono',monospace;white-space:nowrap}
.viznote{font-size:12.5px;color:var(--faint);padding:0 2px}
.vizerr{border-radius:12px;padding:12px 14px;font-size:14px;background:var(--badbg);border:1px solid var(--badline);color:var(--badink)}
.vizerr b{display:block;margin-bottom:3px}
.vizstage{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.1fr);gap:12px;align-items:start}
@media (max-width:820px){.vizstage{grid-template-columns:1fr}}
.vizcode{border:1px solid var(--line);border-radius:var(--r);background:var(--code);overflow:auto;
  font-family:'JetBrains Mono',ui-monospace,monospace;font-size:13px;line-height:1.6;padding:8px 0}
.vcl{display:flex;gap:10px;padding:1px 12px;border-left:3px solid transparent}
.vcl.on{background:rgba(124,92,255,.16);border-left-color:var(--acc)}
.vcl .vcn{color:var(--gutink);user-select:none;min-width:20px;text-align:right;flex:none}
.vcl .vct{white-space:pre-wrap;overflow-wrap:anywhere}
.vizmem{position:relative;display:flex;gap:22px;flex-wrap:wrap;border:1px solid var(--line);border-radius:var(--r);
  background:var(--panel);padding:14px;min-height:120px}
.vizarrows{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none;overflow:visible;z-index:2}
.vizvars{display:flex;flex-direction:column;gap:8px;position:relative;z-index:1;min-width:120px}
.vizvar{display:flex;align-items:center;gap:6px;background:var(--sunken);border:1px solid var(--line);
  border-radius:9px;padding:5px 9px;font-family:'JetBrains Mono',monospace;font-size:13px}
.vizvar b{color:var(--acc2);font-weight:600}
.vizvar .veq{color:var(--faint)}
.vizheap{display:flex;flex-direction:column;gap:12px;position:relative;z-index:1;flex:1;min-width:150px}
.vizempty{color:var(--faint);font-style:italic;font-size:13px;align-self:center}
.vizobj{border:2px solid var(--acc);border-radius:12px;background:var(--sunken);padding:8px 10px;align-self:flex-start;max-width:100%}
.vohead{font-size:11px;letter-spacing:.06em;text-transform:uppercase;font-weight:700;margin-bottom:7px}
.vohead .vonames{color:var(--faint);text-transform:none;letter-spacing:0;font-weight:500;font-family:'JetBrains Mono',monospace}
.vocells{display:flex;flex-wrap:wrap;gap:6px}
.vocell{display:flex;flex-direction:column;align-items:center;gap:2px;min-width:34px}
.vocell .voidx{font-size:10px;color:var(--faint);font-family:'JetBrains Mono',monospace}
.vocell .voval{border:1px solid var(--line2);border-radius:7px;background:var(--code);padding:4px 8px;
  font-family:'JetBrains Mono',monospace;font-size:13px;min-width:22px;text-align:center}
.vodict{display:flex;flex-direction:column;gap:5px}
.vopair{display:flex;align-items:center;gap:5px;font-family:'JetBrains Mono',monospace;font-size:13px}
.vopair .vokey{background:var(--code);border:1px solid var(--line2);border-radius:6px;padding:2px 7px;color:var(--codeink)}
.vopair .vosep{color:var(--faint)}
.voempty{color:var(--faint);font-style:italic;font-size:12.5px}
.vval{font-family:'JetBrains Mono',monospace;font-size:13px;color:var(--ink)}
.voval .vval{color:inherit}
.vref{display:inline-block;border:1px solid;border-radius:6px;padding:0 7px;font-weight:800;line-height:1.5}

/* ---------- визуализатор: что изменилось на шаге и стек вызовов ---------- */
/* Внимание: тут flex, поэтому текст фразы обязан лежать в одном .vwt.
   Если положить его прямо в .vizwhat, каждый <b> станет flex-элементом и
   фраза расползётся по зазорам — «всего: 0 → 12» превратится в «всего : 0 → 12». */
.vizwhat{display:flex;flex-wrap:wrap;gap:9px;align-items:baseline;font-size:13.5px;color:var(--ink);
  background:rgba(0,224,184,.09);border:1px solid var(--acc2line);border-radius:12px;padding:9px 13px}
.vizwhat .vwl{font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--acc2);flex:none;
  padding-top:2px}
.vizwhat .vwt{flex:1 1 auto;min-width:0}
.vizwhat b{font-family:'JetBrains Mono',monospace;font-weight:600;color:var(--okink)}
/* Две метки: «новое» тёплая, «изменилось» бирюзовая. Разные цвета, потому что
   это разные события: появилось имя или поменялось значение у прежнего. */
.vzn{border-color:var(--gold) !important;box-shadow:0 0 0 2px rgba(255,197,61,.18)}
.vzc{border-color:var(--acc2) !important;box-shadow:0 0 0 2px rgba(0,224,184,.16)}
.vocell.vzn .voval,.vocell.vzc .voval{border-color:inherit}
.vopair.vzn,.vopair.vzc{border:1px solid;border-radius:8px;padding:2px 5px;margin:-3px -6px}
.vizscope{display:flex;flex-direction:column;gap:7px;border:1px dashed var(--line2);border-radius:12px;padding:9px 10px}
.vizscope.call{border-style:solid;background:rgba(124,92,255,.07)}
.vizscope .vsname{font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--faint);
  font-weight:700;font-family:'JetBrains Mono',monospace}
.vizscope.call .vsname{color:var(--accink)}
.vizscope .vsfn{text-transform:none;letter-spacing:.02em;font-size:12px}
.vizvars>.vizscope+.vizscope{margin-top:2px}
@media (prefers-reduced-motion:no-preference){
  .vzn,.vzc{animation:vzpop .35s cubic-bezier(.2,1.3,.4,1)}
}
@keyframes vzpop{from{transform:scale(.9)}to{transform:scale(1)}}

.edit-area{position:relative;display:flex;min-height:190px}
.gutter{flex:none;padding:12px 8px 12px 12px;text-align:right;color:var(--gutink);font-size:13.5px;line-height:1.62;
  user-select:none;background:var(--gut);border-right:1px solid var(--line);min-width:42px}
.gutter i{display:block;font-style:normal;transition:.2s;border-radius:3px}
.gutter i.err{color:var(--onacc);background:var(--bad);margin-right:-4px;padding-right:4px}
.gutter i.cur{color:var(--onacc2);background:var(--acc2);margin-right:-4px;padding-right:4px}
/* Строка с пометкой взрослого. ⚠️ Слабее ошибки и слабее текущей строки:
   пометка это «посмотри сюда», а не «здесь сломано». Точка вместо заливки —
   номер остаётся читаемым, а глаз всё равно её находит. */
.gutter i.note{color:var(--acc);font-weight:700}
.gutter i.note::after{content:"•";margin-left:2px}
.edit-scroll{position:relative;flex:1;min-width:0}
.edit-scroll pre.hl,.edit-scroll textarea{
  margin:0;padding:12px 14px;font-size:13.5px;line-height:1.62;
  white-space:pre-wrap;overflow-wrap:anywhere;tab-size:4;border:0;
}
.edit-scroll pre.hl{position:absolute;top:0;left:0;right:0;bottom:0;pointer-events:none;color:var(--ink);overflow:hidden}
.edit-scroll textarea{position:relative;width:100%;min-height:190px;height:auto;background:transparent;color:transparent;
  caret-color:var(--acc2);resize:none;outline:none;display:block;overflow:hidden}
.edit-scroll textarea::selection{background:rgba(124,92,255,.45);color:transparent}

.runbar{display:flex;gap:8px;flex-wrap:wrap;align-items:center;padding:10px 12px;background:var(--bar);border-top:1px solid var(--line)}
.runbar .sp{flex:1}
.runbar .tip,.hintbox .tip{font-size:11.5px;color:var(--faint)}
.rbtn{border:0;border-radius:10px;padding:9px 16px;font-size:13.5px;font-weight:700;cursor:pointer;transition:.15s;
  background:linear-gradient(135deg,var(--acc2-lt),var(--acc2));color:var(--onacc2)}
.rbtn:hover{transform:translateY(-1px)}
.rbtn.sec{background:var(--panel2);color:var(--soft);border:1px solid var(--line2)}
.rbtn.sec:hover{color:var(--ink);border-color:var(--acc)}
.rbtn.check{background:linear-gradient(135deg,var(--acc),var(--acc-lt));color:var(--onacc)}

.side{display:flex;flex-direction:column;gap:12px}
.pane{border:1px solid var(--line);border-radius:var(--r);background:var(--panel);overflow:hidden;box-shadow:var(--sh)}
.pane .ph{padding:8px 13px;font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--faint);font-weight:700;border-bottom:1px solid var(--line);background:var(--panehead)}
.pane .pb{padding:12px 14px;font-size:13.5px}
.console{background:var(--sunken);min-height:90px;max-height:280px;overflow:auto;white-space:pre-wrap;
  color:var(--outink);font-size:13px;line-height:1.55;padding:12px 14px;font-family:'JetBrains Mono',monospace}
.console .empty,.varlist .empty{color:var(--faint);font-style:italic;font-family:'Inter'}
/* «Показать страницей» (js/studio.js): HTML из вывода — настоящей страницей.
   Лист белый в ЛЮБОЙ теме: так его увидит посетитель сайта, и тёмная рамка
   вокруг чужой страницы читалась бы как часть самой страницы. */
.pagebar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:8px 13px;border-top:1px solid var(--line)}
.pagebar .tip{font-size:12.5px;color:var(--faint)}
.pagebox{border-top:1px solid var(--line);padding:10px 13px}
.pageframe{display:block;width:100%;height:220px;border:1px solid var(--line2);border-radius:10px;background:#fff}
.pagenote{margin-top:8px;font-size:13.5px;color:var(--soft)}
.pagenote:empty{display:none}
/* ---- раздел «HTML и CSS» (js/screens-web.js): код слева, страница справа ---- */
.wbwrap{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:18px;margin:0 0 16px}
.wbcode{min-height:300px}
.wbframe{min-height:300px}
.wbright .pagenote{margin:8px 0 0}
.wbex{margin-top:10px}
.wbex pre{background:var(--sunken);border-radius:10px;padding:10px 12px;margin:6px 0 0;
  overflow:auto;font-family:'JetBrains Mono',monospace;font-size:13.5px}
.wbchecks{list-style:none;margin:10px 0 0;padding:0;display:grid;gap:6px}
.wbchecks li{display:flex;gap:8px;align-items:baseline;line-height:1.45;color:var(--soft);font-size:14px}
.wbchecks .mk{flex:none;width:18px;text-align:center;font-weight:700}
.wbchecks .ok .mk{color:var(--ok)}
.wbchecks .bad .mk{color:var(--bad)}
.wbchecks .wait .mk{color:var(--faint)}
.wbkeys{margin-top:6px}
@media (max-width:860px){ .wbwrap{grid-template-columns:minmax(0,1fr)} }

/* ---- пакет к защите проекта (js/screens-defense.js) ----
   Документы — бумага: лист белый в любой теме, шрифт с засечками, как в
   школьных работах. Каждый .docpage при печати — отдельная страница. */
.deffield{display:grid;gap:4px;margin:14px 0 0}
.deffield textarea{width:100%;box-sizing:border-box;background:var(--panel);color:var(--ink);
  border:1px solid var(--line2);border-radius:10px;padding:10px 12px;font:inherit;resize:vertical}
.deffield textarea:focus{outline:none;border-color:var(--acc)}
.defdocs{display:grid;gap:12px}
.defdoc{display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap;margin:0}
.defdoc h3{margin:0 0 4px}
.defdoc p{margin:0}
.doc{position:fixed;inset:0;z-index:70;background:var(--scrim);overflow:auto;padding:20px 14px}
.doc[hidden]{display:none}
.docwrap{width:min(860px,100%);margin:0 auto}
.docbar{display:flex;gap:10px;flex-wrap:wrap;justify-content:center;margin:0 0 14px}
.docpage{background:#fff;color:#1b1b1b;border-radius:6px;padding:48px 52px;margin:0 0 18px;
  box-shadow:0 18px 50px -20px rgba(0,0,0,.6);font:15px/1.6 Georgia,'Times New Roman',serif}
.docpage h1{font:700 24px/1.3 Georgia,'Times New Roman',serif;margin:0 0 14px}
.docpage h2{font:700 18px/1.3 Georgia,'Times New Roman',serif;margin:24px 0 8px}
.docpage table{width:100%;border-collapse:collapse;margin:8px 0}
.docpage th,.docpage td{border:1px solid #999;padding:6px 8px;text-align:left;vertical-align:top;font-size:14px}
.docpage th{background:#f3f3f3;width:26%}
.docpage pre{background:#f5f5f5;border:1px solid #ddd;border-radius:4px;padding:10px 12px;margin:6px 0;
  font:12.5px/1.45 'JetBrains Mono',monospace;white-space:pre-wrap;overflow-wrap:anywhere}
.dockicker{font:12px/1.4 sans-serif;letter-spacing:.08em;text-transform:uppercase;color:#666;margin:0 0 6px}
.docnote{font-size:12.5px;color:#555}
.docblank{display:block;border-bottom:1px solid #888;height:26px}
.docinline{display:inline-block;min-width:180px;border-bottom:1px solid #888;height:1em;vertical-align:baseline}
.docinline.short{min-width:56px}
.doctitle{display:flex;flex-direction:column;justify-content:space-between;min-height:900px}
.doccenter{text-align:center}
.docright{align-self:flex-end;text-align:left}
.docslide{min-height:520px;display:flex;flex-direction:column;justify-content:center}
.docslide h1{font-size:32px}
.docslide p,.docslide li{font-size:19px}
.docthanks{margin-top:24px;font-weight:700}
.docqs li{margin:0 0 12px}
.docans{margin:4px 0 0;font-size:13.5px}
@media (max-width:720px){ .docpage{padding:28px 20px} .doctitle{min-height:600px} }
/* Правила печати документов — НЕ здесь, а в общем блоке @media print рядом
   с сертификатом: всё прячет одно правило body>*, и возвращать на бумагу
   надо в том же месте (RAZVITIE § 4.18). */
canvas.stage{display:block;width:100%;height:auto;background:var(--board)}
.varlist{display:flex;flex-direction:column;gap:5px}
.varrow{display:flex;gap:8px;align-items:baseline;font-size:13px}
.varrow b{color:var(--acc2);font-weight:600;font-family:'JetBrains Mono'}
.varrow span{color:var(--soft);font-family:'JetBrains Mono';word-break:break-all}
.varrow em{color:var(--faint);font-style:normal;font-size:11px;margin-left:auto;flex:none}

.msg{border-radius:13px;padding:14px 16px;margin-top:12px;font-size:14.5px;display:none;animation:pop .28s cubic-bezier(.2,1.2,.4,1)}
.msg.show{display:block}
.msg.ok{background:var(--okbg);border:1px solid var(--okline);color:var(--okink)}
.msg.bad{background:var(--badbg);border:1px solid var(--badline);color:var(--badink)}
.msg.warn{background:var(--warnbg);border:1px solid var(--warnline);color:var(--warnink)}
/* Нейтральная плашка режима экзамена. ⚠️ Она обязана быть НИ зелёной, ни
   красной: одно и то же сообщение показывается и на верный, и на неверный
   ответ, и цвет выдал бы то, о чём молчат слова. */
.msg.info{background:var(--sunk2);border:1px solid var(--line);color:var(--ink)}
.msg b{display:block;margin-bottom:4px;font-size:15px}
/* Часы экзамена: в шапке задачи и на экране варианта. Последние пять минут —
   тревожным цветом: «осталось 4:12» мелким серым не читается вовсе. */
.examclock{display:inline-block;font-family:'JetBrains Mono';font-size:15px;font-weight:600;
  background:var(--sunk2);border:1px solid var(--line);border-radius:11px;padding:6px 11px}
.examclock.soon{background:var(--badbg);border-color:var(--badline);color:var(--badink)}
.msg .cmp{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px;font-family:'JetBrains Mono';font-size:12.5px}
.msg .cmp div{background:var(--sunk2);border-radius:9px;padding:9px 11px;overflow-x:auto;white-space:pre}
.msg .cmp u{display:block;text-decoration:none;font-family:'Inter';font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--faint);margin-bottom:5px}
@keyframes pop{from{opacity:0;transform:scale(.97) translateY(6px)}to{opacity:1;transform:none}}

.hintbox{margin-top:10px;display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.hintout{margin-top:10px;display:none;background:var(--warnbg);border:1px solid var(--warnline);border-radius:12px;padding:12px 15px;font-size:14px;color:var(--warnink)}
.hintout.show{display:block}
.hintout .step{margin-bottom:7px}
.hintout .step:last-child{margin-bottom:0}
/* Код внутри текста подсказки: тем же «чипом», что и в теории, — чтобы
   print(left) не сливался с обычными словами. Пример-программа — отдельным
   блоком с подписью: ребёнок видит приём глазами, а не восстанавливает его
   из хвоста предложения. */
.hintout .step code{background:var(--sunken);border:1px solid var(--line);border-radius:5px;padding:1px 6px;font-size:.9em;color:var(--codeink);white-space:pre-wrap;overflow-wrap:anywhere}
.hintout .hintex{margin:8px 0 3px 20px}
.hintout .hintexlbl{display:block;font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--faint);margin-bottom:4px}
.hintout .hintcode{margin:0;background:var(--sunken);border:1px solid var(--line);border-radius:9px;padding:9px 12px;font-size:13px;line-height:1.55;color:var(--codeink);overflow-x:auto;white-space:pre}

.pager{display:flex;gap:10px;margin-top:26px;padding-top:20px;border-top:1px solid var(--line);flex-wrap:wrap}
.pager .sp{flex:1}

.ref{display:flex;flex-wrap:wrap;gap:6px}
.ref span{font-family:'JetBrains Mono';font-size:11.5px;background:var(--sunken);border:1px solid var(--line);border-radius:6px;padding:2px 7px;color:var(--codeink);cursor:pointer}
.ref span:hover{border-color:var(--acc2);color:var(--acc2)}

/* ---------- победа ---------- */
/* ⚠️ Окно победы ОБЯЗАНО прокручиваться. Внутрь его карточки складываются
   заметки — про занятие, про щит, про ревью кода, — и на невысоком экране
   (телефон в альбомной ориентации, да и обычный iPhone SE) карточка
   перерастает экран. Без прокрутки grid-центрирование выносит низ карточки
   за пределы окна БЕЗ полосы прокрутки: ребёнок прошёл урок и физически не
   может нажать «Дальше →». Поэтому overflow здесь, а не «на всякий случай»:
   align-items:start не даёт верху уехать под срез, когда карточка выше окна. */
.win{position:fixed;inset:0;z-index:100;background:var(--scrim);backdrop-filter:blur(6px);display:none;
  justify-items:center;align-items:start;padding:20px;overflow-y:auto;overscroll-behavior:contain}
.win.show{display:grid}
.wincard{background:var(--modal);border:1px solid var(--line2);border-radius:24px;
  padding:32px 34px;max-width:440px;width:100%;text-align:center;box-shadow:var(--shbig);
  margin:auto;animation:pop .4s cubic-bezier(.2,1.3,.4,1)}
.wincard .big{font-size:52px;line-height:1;margin-bottom:6px}
.wincard h2{margin:0 0 6px;font-size:26px}
.wincard p{margin:0 0 16px;color:var(--soft)}
.winstars{font-size:38px;letter-spacing:6px;color:var(--staroff);margin-bottom:10px}
.winstars b{color:var(--gold);font-weight:400;display:inline-block;animation:star .5s cubic-bezier(.2,1.4,.4,1) backwards}
.winstars b:nth-child(1){animation-delay:.05s}.winstars b:nth-child(2){animation-delay:.2s}.winstars b:nth-child(3){animation-delay:.35s}
@keyframes star{from{opacity:0;transform:scale(0) rotate(-60deg)}to{opacity:1;transform:none}}
.winxp{color:var(--acc2);font-weight:700;margin-bottom:16px}
.winrow{display:flex;gap:10px;justify-content:center;flex-wrap:wrap}
/* Имя после первой победы: гостю, и только ему (winSaveHTML в app.js). */
.winsave{margin:0 0 18px;padding-top:16px;border-top:1px solid var(--line2);text-align:left}
.winsave>b{display:block;margin-bottom:4px}
.wincard .winsave p{margin:0 0 10px}
.winsave .ldauthrow{gap:8px}
.wincard .winsaved{margin:0;color:var(--ink)}
canvas#confetti{position:fixed;inset:0;pointer-events:none;z-index:99;display:none}

/* Всплывашка стоит ВЫШЕ кнопки «наверх»: раньше у обеих было bottom:16px,
   и сообщение о новом бейдже накрывало кнопку целиком — как раз на длинной
   странице урока, где она и нужна. */
.toast{position:fixed;right:16px;bottom:70px;z-index:120;background:var(--modal);
  border:1px solid var(--gold);border-radius:14px;padding:12px 16px;box-shadow:var(--shbig);
  display:flex;gap:10px;align-items:center;font-size:14px;animation:pop .35s cubic-bezier(.2,1.3,.4,1);transition:.4s}
.toast.out{opacity:0;transform:translateY(10px)}
.toast .em{font-size:24px}
.toast b{display:block}
.toast span span{color:var(--soft);font-size:13px}

/* ---------- фокус ---------- */
body.focus .xpbox,body.focus .starcount{display:none}
body.focus .card.theory{display:none}
body.focus .lede{display:none}

.kbd{display:inline-block;background:var(--sunken);border:1px solid var(--line2);border-bottom-width:2px;
  border-radius:5px;padding:0 5px;font-size:11.5px;font-family:'JetBrains Mono';color:var(--soft)}

@media (max-width:640px){
  /* На телефоне подсказка «Ctrl+Enter» бесполезна — клавиши Ctrl там нет, —
     а место занимает. С пятой кнопкой («Разобрать») панель запуска на узком
     экране выросла с двух строк до трёх, поэтому здесь она сжимается: тип
     подсказки убран, а кнопки — плотнее. Проверено на 375px: пять кнопок
     снова укладываются в две строки. */
  .runbar .tip,.runbar .sp{display:none}
  .runbar .rbtn{padding:8px 11px;font-size:13px}
  .wrap{padding:18px 12px 70px}
  .hero{padding:22px 18px;border-radius:18px}
  .hero h1{font-size:27px}
  .lvlhead h1{font-size:24px}
  .card{padding:15px 15px}
  .msg .cmp{grid-template-columns:1fr}
  .logo b{font-size:17px}
  .xpbar{width:70px}
  .worlds{grid-template-columns:1fr}
  /* ⚠️ Шестнадцать пикселей здесь — не про красоту, а про то, чтобы страница
     не прыгала. Safari на iPhone САМ увеличивает масштаб, когда палец попадает
     в поле со шрифтом мельче 16px, и обратно уже не возвращает: после первого
     же тапа в редактор шапка и кнопки «Запустить/Проверить» уезжают за правый
     край, и ребёнок ищет их, возя пальцем по горизонтали. Ровно 16px — порог,
     при котором зума не происходит. Заодно на телефоне попросту крупнее.
     Имя ученика при регистрации уже было 16px по этой же причине. */
  .edit-scroll pre.hl,.edit-scroll textarea,
  .lsearch input,.sheethead input[type=search],.playbar .playin,
  .memin,.stdinbox,.specin,.admgate input,.admlbl input,.admjson,.lblin{font-size:16px}
  /* Номера строк обязаны совпасть с кодом по кеглю и межстрочью, иначе
     разъедутся (высоту строк редактора выравнивает syncGutter в app.js). */
  .gutter{font-size:16px}
}
@media (prefers-reduced-motion:reduce){*{animation-duration:.01ms !important;transition-duration:.01ms !important}}

/* ---------- задание «найди и почини ошибку» ---------- */
.bugcard{background:var(--bugbg);border:1px solid var(--bugline);border-radius:var(--r);padding:16px 20px;margin:0 0 14px}
.bugcard h3{margin:0 0 6px;font-size:17px;color:var(--bugink)}
.bugcard p{margin:0 0 9px;color:var(--ink)}
.bugcard code{background:var(--sunk2);border:1px solid var(--bugline);border-radius:5px;padding:1px 6px;font-size:.86em;color:var(--bugink)}
.bugcard .bugtip{display:block;font-size:12.5px;color:var(--soft)}
.demo .bar .hintx.errx{color:var(--warn)}

/* ---------- задание «вынеси вердикт» (тип review в «Ты и ИИ») ---------- */
.claimcard{background:var(--claimbg);border:1px solid var(--line2);border-radius:var(--r);padding:16px 20px;margin:0 0 14px}
.claimcard h3{margin:0 0 6px;font-size:17px;color:var(--claimink)}
.claimcard p{margin:0 0 9px;color:var(--ink);font-size:16.5px}
.claimcard .claimtip{display:block;font-size:12.5px;color:var(--faint)}
.verdict{background:var(--panel);border:1px solid var(--line2);border-radius:var(--r);padding:18px 20px;margin:16px 0 0}
.verdict h3{margin:0 0 6px;font-size:18px}
.verdict > p{margin:0 0 13px;color:var(--soft);font-size:14.5px}
.vbtns{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:10px}
.vbtn{display:block;text-align:left;background:var(--panel2);border:1px solid var(--line2);border-radius:12px;
      padding:12px 15px;color:var(--ink);cursor:pointer;transition:.15s;font-size:14px}
.vbtn:hover{border-color:var(--acc);transform:translateY(-1px)}
.vbtn.on{border-color:var(--acc);background:rgba(124,92,255,.16)}
.vbtn b{display:block;font-size:15px;margin-bottom:3px}
.vbtn span{display:block;color:var(--faint);font-size:12.5px;line-height:1.45}
.vpick{margin-top:12px}
.lines{background:var(--code);border:1px solid var(--line);border-radius:12px;padding:7px 0;overflow-x:auto}
.lrow{display:flex;align-items:flex-start;gap:12px;width:100%;background:none;border:0;border-left:3px solid transparent;
      padding:2px 14px 2px 11px;text-align:left;cursor:pointer;font-family:'JetBrains Mono',ui-monospace,monospace;font-size:13px;line-height:1.7}
.lrow:hover{background:rgba(124,92,255,.13);border-left-color:var(--acc)}
.lrow.on{background:rgba(124,92,255,.2);border-left-color:var(--acc)}
.lrow.off{cursor:default;opacity:var(--dim2)}
.lrow.off:hover{background:none;border-left-color:transparent}
.lrow .ln{flex:none;width:22px;text-align:right;color:var(--c);user-select:none}
.lrow code{white-space:pre;color:var(--ink)}
.proof{margin:12px 0 4px;text-align:left;font-size:13.5px;color:var(--soft)}
.proof u{display:block;text-decoration:none;font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--faint);margin-bottom:6px}
.proof .cmp{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:9px;font-family:'JetBrains Mono';font-size:12.5px}
.proof .cmp div{background:var(--sunk2);border-radius:9px;padding:9px 11px;overflow-x:auto;white-space:pre}
.proof .cmp u{margin-bottom:5px}
@media (max-width:620px){
  .proof .cmp{grid-template-columns:1fr}
}

/* ---------- панель репетитора ---------- */
.admgate{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
.admgate input{flex:1 1 220px;min-width:0;background:var(--sunken);border:1px solid var(--line2);border-radius:10px;padding:10px 13px;color:var(--ink);font-size:14px;font-family:'Inter',sans-serif}
.admgate input:focus{outline:none;border-color:var(--acc)}
.admstats{display:grid;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));gap:10px;margin-bottom:18px}
.admstat{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:11px 14px}
.admstat span{display:block;font-size:11px;letter-spacing:.07em;text-transform:uppercase;color:var(--faint)}
.admstat b{font-size:19px;font-family:'Fredoka','Inter',sans-serif;font-weight:600}
.admrow{display:flex;gap:9px;flex-wrap:wrap;align-items:center;margin:6px 0 4px}
.admlbl{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--soft)}
.admlbl input{width:118px;background:var(--sunken);border:1px solid var(--line2);border-radius:9px;padding:8px 10px;color:var(--ink);font-size:14px;font-family:'JetBrains Mono',monospace}
.admlbl input:focus{outline:none;border-color:var(--acc)}
.admbadges{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px}
.admbadge{display:flex;align-items:center;gap:7px;background:var(--sunken);border:1px solid var(--line);border-radius:99px;padding:6px 13px;color:var(--faint);font-size:12.5px;font-weight:600;cursor:pointer;transition:.15s}
.admbadge .em{font-size:14px;filter:grayscale(1);opacity:.6}
.admbadge.got{background:rgba(255,197,61,.11);border-color:var(--gold);color:var(--gold)}
.admbadge.got .em{filter:none;opacity:1}
.admbadge:hover{border-color:var(--acc);color:var(--ink)}
.admtable{border:1px solid var(--line);border-radius:12px;overflow-x:auto;margin-bottom:20px;background:var(--panel)}
.admhead,.admrowl{display:grid;grid-template-columns:44px minmax(150px,1.5fr) 64px 76px 88px 84px 88px 132px minmax(210px,auto);gap:6px;align-items:center;padding:8px 12px;font-size:12.5px}
.admhead{background:var(--panel2);color:var(--faint);font-size:10.5px;letter-spacing:.06em;text-transform:uppercase}
.admrowl{border-top:1px solid var(--line);color:var(--soft)}
.admrowl.soon{opacity:var(--dim)}
.admrowl .n{color:var(--faint);font-weight:700}
.admrowl .t{color:var(--ink);font-weight:600}
.admrowl .t em{font-style:normal;font-size:10px;color:var(--faint);border:1px solid var(--line2);border-radius:5px;padding:1px 5px;margin-left:5px;vertical-align:1px}
.admrowl .stars{color:var(--staroff);letter-spacing:1px}
.admrowl .stars b{color:var(--gold)}
.admrowl .acts{display:flex;gap:5px;flex-wrap:wrap;justify-content:flex-end}
.admrowl .acts .minibtn{padding:3px 9px;font-size:11.5px}
.admwide{min-width:900px}
.admjson{width:100%;height:150px;background:var(--sunken);border:1px solid var(--line2);border-radius:11px;padding:11px 13px;color:var(--soft);font-size:12px;line-height:1.5;resize:vertical;margin:8px 0 4px}
.admjson:focus{outline:none;border-color:var(--acc)}
.admlist{display:flex;flex-direction:column;gap:6px;margin-top:9px}
.admlrow{display:flex;align-items:center;gap:10px;background:var(--sunk2);border-radius:9px;padding:7px 11px;flex-wrap:wrap}
.admlrow b{font-family:'JetBrains Mono',monospace;font-size:12.5px;color:var(--ink)}
.admlrow span{font-size:12px;color:var(--soft);margin-right:auto}
.admlbl input[type=text],.admlbl input[type=password]{width:190px;font-family:'JetBrains Mono',monospace;font-size:13px}

/* ---------- раздел «Повторить»: интервальный повтор ---------- */
.tbtn.again.due{border-color:var(--acc2);color:var(--ink);animation:duepulse 1.8s ease-in-out infinite}
.revlist{display:flex;flex-direction:column;gap:10px}
.revlist.later{opacity:.62}
.revcard{display:flex;align-items:center;gap:14px;width:100%;text-align:left;cursor:pointer;
  border:1px solid var(--line);background:var(--panel);border-radius:var(--r);
  padding:13px 16px;color:var(--ink);font:inherit;transition:.15s}
.revcard:hover{border-color:var(--acc);background:var(--panel2)}
.revcard .rvicon{font-size:22px;flex:none}
.revcard .rvbody{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
.revcard .rvkicker{font-size:11.5px;color:var(--faint);text-transform:uppercase;letter-spacing:.05em}
.revcard .rvbody b{font-size:15.5px}
.revcard .rvbody>span:last-child{color:var(--soft);font-size:13.5px}
.revcard .rvright{display:flex;flex-direction:column;align-items:flex-end;gap:7px;flex:none}
.revcard .rvwhen{font-size:12.5px;color:var(--soft);white-space:nowrap}
.revlist:not(.later) .rvwhen{color:var(--acc2);font-weight:700}
.rdots{display:flex;gap:4px}
.rdot{width:7px;height:7px;border-radius:99px;background:var(--sunken);border:1px solid var(--line2)}
.rdot.on{background:var(--acc2);border-color:transparent}
.revnote{margin:8px 0 0;font-size:13.5px;color:var(--soft)}
@media (max-width:620px){
  .revcard{flex-wrap:wrap}
  .revcard .rvright{flex-direction:row;align-items:center;width:100%;justify-content:space-between}
}

/* ---------- шпаргалка: оверлей поверх любого экрана ---------- */
.sheet{position:fixed;inset:0;z-index:60;background:var(--scrim);
  display:flex;align-items:flex-start;justify-content:center;padding:40px 16px}
.sheet[hidden]{display:none}
.sheetbox{width:min(760px,100%);max-height:calc(100vh - 80px);display:flex;flex-direction:column;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--sh);overflow:hidden}
.sheethead{display:flex;align-items:center;gap:12px;padding:14px 16px;border-bottom:1px solid var(--line);
  background:var(--panel2);flex-wrap:wrap}
.sheethead>b{font-family:'Fredoka','Inter',sans-serif;font-size:17px;white-space:nowrap}
.sheethead input[type=search]{flex:1;min-width:160px;background:var(--sunken);color:var(--ink);
  border:1px solid var(--line2);border-radius:10px;padding:8px 12px;font:inherit;font-size:14px}
.sheethead input[type=search]:focus{outline:none;border-color:var(--acc)}
.sheetall{display:flex;align-items:center;gap:6px;color:var(--soft);font-size:13px;white-space:nowrap;cursor:pointer}
.sheetbody{overflow-y:auto;padding:6px 16px 18px}
.shgroup{margin-top:16px}
.shgroup h4{margin:0 0 8px;font-size:12.5px;text-transform:uppercase;letter-spacing:.06em;color:var(--faint)}
.shitem{border:1px solid var(--line);border-radius:12px;padding:12px 14px;margin-bottom:9px;background:var(--sunken)}
.shitem.soon{opacity:var(--dim2)}
.shsig{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.shsig code{font-size:14px;color:var(--acc2);font-weight:600}
.shsoon{font-size:11px;color:var(--faint);border:1px solid var(--line2);border-radius:99px;padding:1px 8px}
.shwhat{margin:5px 0 9px;color:var(--soft);font-size:13.5px}
.shcode{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.shcode pre{margin:0;padding:9px 11px;border-radius:9px;background:var(--panel);border:1px solid var(--line);
  font-size:12.5px;line-height:1.5;
  white-space:pre;overflow-x:auto}
.shcode .shout{background:rgba(0,224,184,.07);border-color:rgba(0,224,184,.28);color:var(--ink)}
.shfrom{margin-top:8px;font-size:11.5px;color:var(--faint)}
.shempty{color:var(--soft);font-size:14px;margin:18px 0 4px}
@media (max-width:640px){
  .sheet{padding:12px 8px}
  .sheetbox{max-height:calc(100vh - 24px)}
  .shcode{grid-template-columns:1fr}
}

/* ---------- отчёт за неделю в панели репетитора ---------- */
.weekrep .wrline{margin:0 0 14px;font-size:15px;color:var(--ink)}
.weekrep .wrline b{color:var(--acc2)}
.wrstrip{display:flex;gap:8px;flex-wrap:wrap}
.wrday{display:flex;flex-direction:column;align-items:center;gap:3px;width:52px;padding:8px 0;
  border:1px solid var(--line);border-radius:11px;background:var(--sunken)}
.wrday.on{border-color:var(--ok);background:rgba(61,220,132,.10)}
.wrday.shield{border-color:var(--acc2);background:rgba(0,224,184,.08)}
.wrday.now{box-shadow:0 0 0 2px rgba(124,92,255,.35)}
.wrday .wrd{font-size:10.5px;color:var(--faint);text-transform:uppercase;letter-spacing:.04em}
.wrday .wrn{font-size:17px;font-weight:700;line-height:1.1}
.wrday.on .wrn{color:var(--ok)}
.wrday .wrdate{font-size:10.5px;color:var(--faint)}
.wrtough{margin-top:14px;border-top:1px solid var(--line);padding-top:12px}
.wrtough ul{margin:6px 0 0;padding-left:20px;color:var(--soft);font-size:14px}
.wrtough li{margin-bottom:3px}
.wrnext{margin:14px 0 0;padding-top:12px;border-top:1px solid var(--line);font-size:14.5px;color:var(--soft)}
.wrnext b{color:var(--ink)}

/* ---------- разминка «предскажи память» ---------- */
.memq .mlines{padding:12px 0;font:13px/1.7 'JetBrains Mono',ui-monospace,monospace;overflow-x:auto}
.mline{display:flex;align-items:baseline;gap:10px;padding:1px 14px;white-space:pre}
.mline .ln{color:var(--faint);font-size:11.5px;min-width:20px;text-align:right;flex:none;user-select:none}
.mline.here{background:rgba(124,92,255,.16);box-shadow:inset 3px 0 0 var(--acc)}
.mline .mstop{margin-left:12px;font-family:'Inter',sans-serif;font-size:11.5px;color:var(--acc);
  white-space:nowrap;letter-spacing:.02em}
.memrows{display:flex;flex-direction:column;gap:9px}
.memrow{display:flex;align-items:center;gap:9px}
.memrow>b{font:600 13.5px/1 'JetBrains Mono',ui-monospace,monospace;color:var(--acc2);min-width:84px}
.memrow .veq{color:var(--faint)}
.memin{flex:1;min-width:0;background:var(--sunken);color:var(--ink);border:1px solid var(--line2);
  border-radius:9px;padding:8px 11px;font:13px/1.4 'JetBrains Mono',ui-monospace,monospace}
.memin:focus{outline:none;border-color:var(--acc)}
.memq .vizmem{position:relative;padding:6px 2px}
@media (max-width:620px){
  .memrow{flex-wrap:wrap}
  .memrow>b{min-width:0}
  .mline .mstop{display:none}
}

/* ---------- портфолио: готовые программы и сертификаты ---------- */
.fstats{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin:18px 0 4px}
.fstat{background:var(--panel);border:1px solid var(--line);border-radius:13px;
  padding:14px 16px;text-align:center;box-shadow:var(--sh)}
.fstat b{display:block;font-family:'Fredoka','Inter',sans-serif;font-size:26px;line-height:1.1;color:var(--acc2)}
.fstat b i{font-style:normal;font-size:15px;color:var(--faint)}
.fstat span{display:block;margin-top:3px;font-size:12.5px;color:var(--soft)}

.fproj{border:1px solid var(--line);border-radius:var(--r);background:var(--panel);
  box-shadow:var(--sh);padding:15px 17px;margin-bottom:12px}
.fproj.done{border-color:var(--ok)}
.fproj.locked{border-style:dashed;opacity:.7}
.fptop{display:flex;align-items:center;gap:13px}
.fpttl{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.fpttl b{font-family:'Fredoka','Inter',sans-serif;font-size:18px}
.fpsub{color:var(--soft);font-size:13.5px}
.fpstat{flex:none;font-size:12px;color:var(--faint);border:1px solid var(--line2);
  border-radius:99px;padding:2px 10px;white-space:nowrap}
.fpstat.ok{color:var(--ok);border-color:var(--ok)}
.fpcode{margin:12px 0 0;padding:11px 13px;border-radius:11px;background:var(--code);
  border:1px solid var(--line);font-size:12.5px;line-height:1.55;color:var(--ink);
  white-space:pre;overflow:auto;max-height:280px}
.fpbtns{display:flex;align-items:center;gap:9px;margin-top:11px;flex-wrap:wrap}
.fplen{color:var(--faint);font-size:12px}

.certs{display:grid;grid-template-columns:repeat(2,1fr);gap:10px}
.certcard{display:flex;align-items:center;gap:12px;padding:13px 15px;border-radius:13px;
  border:1px dashed var(--line2);background:var(--panel);opacity:.65}
.certcard.got{opacity:1;border-style:solid;border-color:var(--gold);
  box-shadow:0 0 0 1px rgba(255,197,61,.22),0 10px 24px -16px rgba(255,197,61,.7)}
.cticon{font-size:26px;line-height:1;flex:none}
.ctbody{flex:1;min-width:0;display:flex;flex-direction:column}
.ctbody b{font-size:14.5px}
.ctbody>span{color:var(--faint);font-size:12.5px}
.certcard .rbtn{flex:none}

/* ---------- сертификат: лист бумаги поверх страницы ---------- */
.cert{position:fixed;inset:0;z-index:70;background:var(--scrim);
  display:flex;align-items:flex-start;justify-content:center;padding:32px 16px;overflow:auto}
.cert[hidden]{display:none}
.certwrap{width:min(760px,100%)}
.certsheet{background:#fdfaf1;color:#26201a;border:2px solid #c9b26a;border-radius:6px;
  padding:44px 46px 32px;text-align:center;box-shadow:0 24px 60px -20px rgba(0,0,0,.8);
  background-image:radial-gradient(600px 240px at 50% 0%, #fffdf6 0%, #fdfaf1 70%)}
.certmark{font-family:'Fredoka','Inter',sans-serif;font-size:15px;letter-spacing:.16em;
  text-transform:uppercase;color:#8a7434}
.certkind{margin-top:18px;font-family:'Fredoka','Inter',sans-serif;font-size:30px;
  letter-spacing:.04em;color:#26201a}
.certname{margin-top:22px;font-family:'Fredoka','Inter',sans-serif;font-size:38px;line-height:1.2;
  color:#1c2b6b;word-break:break-word}
.certrule{width:220px;height:2px;margin:16px auto 0;background:#c9b26a}
.certwhat{margin-top:18px;font-size:16px;line-height:1.65;max-width:46ch;
  margin-left:auto;margin-right:auto;color:#3b332a}
.certwhat b{color:#26201a}
.certlist{display:block;margin-top:8px;font-size:13.5px;color:#6a5c48}
/* Код на карточке доступа — самое крупное, что на ней есть после имени: её
   печатают ради одной этой строки, и читать её будут второпях. Моноширинный
   шрифт тут не украшение: в коде встречаются похожие знаки, и «l» от «1»
   отличает именно он. */
.certcode{display:block;margin-top:16px;font-family:'JetBrains Mono',monospace;
  font-size:30px;letter-spacing:.06em;font-weight:700;color:#26201a;word-break:break-all}
.certnote{margin-top:20px;font-size:13.5px;line-height:1.6;color:#6a5c48;max-width:52ch;
  border-top:1px solid #d9c99a;padding-top:14px}
.certstars{margin-top:18px;font-family:'Fredoka','Inter',sans-serif;font-size:22px;color:#a5822a}
.certfoot{margin-top:26px;padding-top:14px;border-top:1px solid #e0d6bd;display:flex;
  justify-content:space-between;gap:12px;font-size:12px;color:#7a6c56;flex-wrap:wrap}
.certlegal{margin-top:10px;font-size:11px;color:#9a8c74}
.certbar{display:flex;gap:10px;justify-content:center;margin-top:16px;flex-wrap:wrap}

@media (max-width:720px){
  .fstats{grid-template-columns:repeat(2,1fr)}
  .certs{grid-template-columns:1fr}
  .certsheet{padding:30px 22px 24px}
  .certkind{font-size:23px}
  .certname{font-size:29px}
}

/* Печать: на бумагу уходит только лист сертификата. Всё остальное — сайт,
   шапка, кнопки самого оверлея — скрыто. Если сертификат не открыт,
   печатать нечего, и это честнее, чем выплюнуть тёмную страницу. */
@media print{
  body{background:#fff !important}
  body>*{display:none !important}
  body>.cert:not([hidden]){display:block !important;position:static;padding:0;
    background:#fff;overflow:visible}
  .certwrap{width:auto}
  .certbar{display:none !important}
  .certsheet{box-shadow:none;border-radius:0;background:#fff;
    -webkit-print-color-adjust:exact;print-color-adjust:exact}
  /* документы к защите (1.142.0): тот же приём, только листов несколько —
     каждый .docpage уходит отдельной страницей */
  body>.doc:not([hidden]){display:block !important;position:static;padding:0;
    background:#fff;overflow:visible}
  .docwrap{width:auto}
  .docbar{display:none !important}
  .docpage{box-shadow:none;border-radius:0;margin:0;padding:0;break-after:page;
    -webkit-print-color-adjust:exact;print-color-adjust:exact}
  .docpage:last-child{break-after:auto}
}

/* ---------- подпись «в редакторе код с прошлого раза» ---------- */
.draftnote{display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  margin:0 0 -4px;padding:9px 14px;border:1px solid var(--line2);border-radius:12px;
  background:var(--sunken);color:var(--soft);font-size:13.5px}
.draftnote[hidden]{display:none}
.draftnote .rbtn{margin-left:auto}

/* закрытая разминка: видно, что впереди есть ещё, и чем она откроется */
.gamecard.locked{opacity:var(--dim2);cursor:default;border-style:dashed}
.gamecard.locked:hover{transform:none}

/* ---------- галерея рисунков ---------- */
/* ---------- полоска «вы смотрите глазами ребёнка» ----------
   Взрослый, попавший на урок с вывески, обязан видеть, где он и как выйти:
   детская навигация в шапке подменяет взрослую, и кабинет из урока не виден. */
.peekbar{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin:0 0 14px;
  padding:10px 15px;border:1px dashed var(--acc2);border-radius:12px;
  background:rgba(0,224,184,.08);font-size:13.5px;color:var(--soft)}
.peekbar b{color:var(--ink)}
.peekbar .pktx{flex:1 1 300px;min-width:0}
.peekbar .rbtn{margin-left:auto;flex:none}

/* ---------- выпускной мира ----------
   Список умений — не украшенная похвала, а перечень, по которому ходят
   пальцем. Поэтому строчка выглядит как строка списка, а не как карточка:
   их восемь-десять подряд, и карточки превратили бы экран в простыню. */
.cando{list-style:none;margin:10px 0 0;padding:0;display:flex;flex-direction:column;gap:6px}
.canitem{display:flex;align-items:center;gap:11px;width:100%;text-align:left;
  padding:9px 12px;border:1px solid transparent;border-radius:10px;
  background:var(--sunken);color:var(--ink);font:inherit;font-size:14px;cursor:pointer;transition:.15s}
.canitem:hover{border-color:var(--acc);background:var(--panel2)}
.cantick{flex:none;width:20px;height:20px;border-radius:50%;background:var(--acc);
  color:var(--onacc);font-size:12px;font-weight:700;display:flex;align-items:center;justify-content:center}
.cantxt{flex:1;min-width:0}
.canwhere{flex:none;font-size:12px;color:var(--faint);white-space:nowrap}
.gradproof,.gradshow{margin-top:14px}
@media (max-width:520px){ .canwhere{display:none} }

/* ---------- карта пути: сто уроков одной дорогой ----------
   Кружки, а не список: список из ста строк читается как перечень дел, а
   дорога — как расстояние. Ряд на мир, в конце ряда веха-проект. */
.pathlink{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin:12px 0}
.pathlink .tip{font-size:12.5px;color:var(--faint)}
.pathnow{margin:14px 0;padding:12px 16px;border:1px dashed var(--line2);border-radius:12px;
  background:rgba(0,224,184,.06);font-size:14px;color:var(--soft);line-height:1.55}
.pathnow b{color:var(--ink)}
.pathmap{display:flex;flex-direction:column;gap:18px;margin:16px 0}
.prow{border:1px solid var(--line);border-radius:14px;padding:13px 15px;background:var(--panel)}
.phead{display:flex;align-items:center;gap:9px;margin:0 0 10px;font-size:14px;color:var(--ink)}
.phead .pico{font-size:19px}
.phead .pcnt{margin-left:auto;font-size:12.5px;color:var(--faint);white-space:nowrap}
/* Запас сверху и между рядами — под флажок «ты здесь». Он висит над кружком,
   и без промежутка налезал бы на заголовок ряда или на кружки строкой выше:
   на узком экране двадцать кружков переносятся, и «ты здесь» может оказаться
   на любой строке. */
.pdots{display:flex;flex-wrap:wrap;gap:20px 6px;padding-top:18px}
.pstep{position:relative;width:30px;height:30px;border-radius:50%;border:1px solid var(--line2);
  background:var(--sunken);color:var(--faint);font-size:12px;font-weight:600;cursor:pointer;
  padding:0;transition:.15s;font-variant-numeric:tabular-nums}
.pstep.done{background:var(--acc);border-color:transparent;color:var(--onacc)}
.pstep.open{background:var(--panel2);border-color:var(--acc2);color:var(--ink)}
.pstep.lock,.pstep.soon{opacity:.45;cursor:default}
.pstep.soon{border-style:dashed}
.pstep:not(:disabled):hover{transform:translateY(-2px);border-color:var(--acc)}
.pstep.here{box-shadow:0 0 0 3px rgba(0,224,184,.35)}
.pflag{position:absolute;left:50%;top:-17px;transform:translateX(-50%);
  font-size:10.5px;font-weight:700;color:var(--acc2);white-space:nowrap;letter-spacing:.2px}
.pmile{display:flex;align-items:center;gap:12px;width:100%;margin:12px 0 0;text-align:left;
  padding:11px 14px;border:1px dashed var(--line2);border-radius:12px;background:var(--sunken);
  color:var(--soft);cursor:pointer;transition:.15s}
.pmile.done{border-style:solid;border-color:var(--acc);background:rgba(0,224,184,.07)}
.pmile.open{border-style:solid}
.pmile:disabled{opacity:.5;cursor:default}
.pmile:not(:disabled):hover{border-color:var(--acc)}
.pmile .pmem{font-size:26px;line-height:1}
.pmile .pmbody{display:flex;flex-direction:column;gap:2px;min-width:0}
.pmile .pmkick{font-size:11px;text-transform:uppercase;letter-spacing:.4px;color:var(--faint)}
.pmile b{color:var(--ink);font-size:14.5px}
.pmile .pmbody>span:last-child{font-size:12.5px;color:var(--faint)}
@media (max-width:520px){
  .pstep{width:27px;height:27px;font-size:11px}
  .pdots{gap:5px}
}

/* ---------- карточка «движок» в песочнице ----------
   Тяжёлый контур включается человеком, и переключатель обязан выглядеть
   как выбор, а не как реклама: обычная карточка, кнопка и честный текст. */
.pyeng.on{border-color:var(--acc2)}
.pyrow{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin:10px 0 0}
.pyrow .tip{font-size:12.5px;color:var(--faint)}
.pybar{flex:0 0 160px;height:8px;border-radius:99px;background:var(--sunken);
  border:1px solid var(--line);overflow:hidden}
.pybar i{display:block;height:100%;width:0;background:linear-gradient(90deg,var(--acc2),var(--acc));
  transition:width .3s linear}
.pypct{font-size:12.5px;color:var(--soft);font-variant-numeric:tabular-nums}

/* Назвать свою программу. Форма прячется до нажатия: два пустых поля под
   редактором выглядели бы обязательными, а называть программу никто не
   обязан — это предложение, а не требование. */
.savework{display:flex;flex-direction:column;gap:7px;margin:16px 0 0}
.savework .tip{font-size:12.5px;color:var(--faint)}
.savework .rbtn{align-self:flex-start}
.workform{display:flex;flex-direction:column;gap:9px;margin:4px 0 0;padding:13px 15px;
  border:1px solid var(--line);border-radius:12px;background:var(--panel)}
.workform label{display:flex;flex-direction:column;gap:4px;font-size:13px;color:var(--soft)}
.workform input{font:inherit;font-size:14px;padding:8px 11px;border:1px solid var(--line2);
  border-radius:9px;background:var(--sunken);color:var(--ink)}
.workform input:focus{outline:2px solid var(--acc2);outline-offset:1px;border-color:transparent}
.workform .row{display:flex;gap:8px;flex-wrap:wrap}

.savepic{display:flex;flex-direction:column;gap:7px;margin:14px 0 0}
.savepic .tip{font-size:12.5px;color:var(--faint)}
.savepic .rbtn{align-self:flex-start}
.pics{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:12px}
.pic{border:1px solid var(--line);border-radius:var(--r);overflow:hidden;background:var(--panel)}
.pic.broken{border-color:var(--bad)}
.picart{display:block;width:100%;background:var(--board)}
.picbody{padding:10px 13px;display:flex;flex-direction:column;gap:3px}
.picbody b{font-size:15px}
.picsub{font-size:12px;color:var(--faint)}
.picbtns{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}
@media (max-width:620px){ .pics{grid-template-columns:1fr} }

/* ---------- пересказ программы словами (в визуализаторе) ---------- */
.story{margin:12px 0 4px;padding:13px 16px;border:1px solid var(--line);
  border-radius:var(--r);background:var(--panel)}
.storyhead{font-family:'Fredoka','Inter',sans-serif;font-size:15px;margin-bottom:8px}
.storylist{margin:0;padding-left:22px;color:var(--soft);font-size:14px}
.storylist li{margin-bottom:3px}
.storylist li.d1{margin-left:16px;color:var(--faint)}
.storylist li.d2{margin-left:32px;color:var(--faint)}
.storyerr{margin:8px 0 0;color:var(--bad);font-size:13.5px}
.storynote{margin:9px 0 0;font-size:12.5px;color:var(--faint)}

/* ---------- вопрос за ужином (в отчёте репетитора) ---------- */
.dinner{margin-top:14px;padding:12px 15px;border:1px solid var(--line2);border-radius:12px;
  background:rgba(255,197,61,.07)}
.dinner b{display:block;color:var(--gold);font-size:13px;margin-bottom:4px}
.dinner p{margin:0 0 5px;font-size:14px}
.dinner .dim{font-size:12.5px}

/* ---------- панель символов: только на телефоне ---------- */
/* За настоящей клавиатурой панель только мешает, поэтому по умолчанию её нет
   вовсе, а появляется она в том же @media, где панель запуска сжимается. */
.keybar{display:none}
@media (max-width:640px){
  .keybar{display:flex;flex-wrap:wrap;gap:5px;padding:7px 8px;
    background:var(--res);border-top:1px solid var(--line)}
  .kbk{flex:none;min-width:34px;border:1px solid var(--line2);background:var(--panel2);
    color:var(--ink);border-radius:8px;padding:7px 0;font-family:'JetBrains Mono',monospace;
    font-size:14px;font-weight:700;cursor:pointer}
  .kbk.wide{min-width:96px;font-family:'Inter',sans-serif;font-size:12.5px;color:var(--soft)}
  .kbk:active{background:var(--acc);color:var(--onacc);border-color:transparent}
}

/* ---------- разбор кода: что можно сделать чище ---------- */
.lintlist{display:flex;flex-direction:column;gap:9px;margin:10px 0 4px}
.lintone{display:flex;flex-direction:column;gap:2px;background:var(--sunken);
  border:1px solid var(--line);border-left:3px solid var(--acc2);
  border-radius:0 10px 10px 0;padding:9px 12px}
.lintone .lintln{font-family:'JetBrains Mono',monospace;font-size:11px;color:var(--faint)}
.lintone b{font-size:14px;color:var(--ink)}
.lintone>span:last-child{font-size:13px;color:var(--soft)}
.linttip{display:block;margin-top:6px;font-size:12px;color:var(--faint)}

/* ---------- бестиарий ошибок ---------- */
/* Три состояния зверя: не встречался (приглушён), встречался (обычный),
   побеждён (зелёная рамка). Разметка одна — отличается только классом. */
.beasts{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:10px}
.beast{display:flex;gap:12px;align-items:flex-start;background:var(--panel);
  border:1px solid var(--line);border-radius:var(--r);padding:13px 15px;opacity:var(--dim2);transition:.2s}
.beast.met{opacity:1;border-color:var(--warn)}
.beast.won{opacity:1;border-color:var(--ok);
  box-shadow:0 0 0 1px rgba(61,220,132,.2),0 8px 20px -14px rgba(61,220,132,.6)}
.beast .bem{font-size:24px;line-height:1.2;flex:none}
.beast .bbody{display:flex;flex-direction:column;gap:3px;min-width:0;flex:1}
.beast .bbody b{font-size:15px}
.beast .bkind{font-family:'JetBrains Mono',monospace;font-size:11.5px;color:var(--faint)}
.beast .bwhat{font-size:13.5px;color:var(--soft)}
.beast .bhow{font-size:12.5px;color:var(--faint)}
.beast .bstat{flex:none;font-size:11.5px;color:var(--soft);text-align:right;white-space:nowrap}
.beast.won .bstat{color:var(--ok);font-weight:700}
.beast .bstat i{display:block;font-style:normal;color:var(--faint);font-weight:400;margin-top:3px}
@media (max-width:620px){
  .beasts{grid-template-columns:1fr}
  .beast .bstat{display:none}
}

/* ---------- значения прямо в редакторе ---------- */
/* Приписка живёт внутри подсветки, поэтому течёт по строке вместе с кодом:
   никакой отдельной колонки нет, и разъехаться с текстом она не может. */
.edit-scroll .wv{margin-left:14px;padding:1px 7px;border-radius:6px;
  background:rgba(0,224,184,.10);border:1px solid rgba(0,224,184,.22);
  color:var(--acc2);font-size:12px}

/* ---------- цель по шагам: перышко у пройденного урока ---------- */
.leanmark{margin-right:7px;font-size:14px;opacity:.9}
.stepnote.lean{color:var(--acc2)}

/* ---------- свои задания: форма автора ---------- */
.tsteps{margin:8px 0 0;padding-left:20px;color:var(--soft)}
.tsteps li{margin-bottom:4px}

/* ============================================================
   ПОМОЩЬ: кнопка «?» и всплывающее окно
   Раньше объяснение «что это за экран и что тут делать» жило только на
   Главном и только пока не пройден первый урок. Дальше ребёнок оставался
   один на один с экраном, которого никогда не видел: «Визуализатор»,
   «Повторить», «Своё задание» — по названию не догадаешься.
   Теперь ответ всегда на одном месте — «?» в правом верхнем углу, — и текст
   в нём МЕНЯЕТСЯ вместе с экраном. Окно всплывает поверх, а не уводит со
   страницы: уход с урока стёр бы написанный код.
   ============================================================ */
.tbtn.help{font-weight:700}
.tbtn.help.on{background:var(--acc);color:var(--onacc);border-color:transparent}

/* На большом экране обёртка НЕ ловит указатель: иначе прозрачное затемнение
   съедало бы прокрутку колесом, и страница за окном «замирала» бы — это
   читается как поломка. Закрытие по клику мимо держится на обработчике в
   js/app.js. На телефоне наоборот: затемнение видно, оно ловит палец и
   закрывает — кнопка «✕» слишком мелкая для пальца. */
.helpwrap{position:fixed;inset:0;z-index:90;display:none;pointer-events:none}
.helpwrap.show{display:block}
.helpwrap .helpveil{position:absolute;inset:0;background:transparent}
.helpwrap .helpbox{pointer-events:auto}
@media (max-width:640px){
  .helpwrap{pointer-events:auto}
  .helpwrap .helpveil{background:var(--scrim)}
}

.helpbox{position:absolute;top:64px;right:16px;width:min(400px,calc(100vw - 32px));
  max-height:min(78vh,720px);display:flex;flex-direction:column;
  background:var(--panel);border:1px solid var(--line2);border-radius:18px;
  box-shadow:var(--shbig);overflow:hidden;animation:pop .2s cubic-bezier(.2,1.2,.4,1)}
@media (max-width:640px){
  .helpbox{top:auto;bottom:0;right:0;left:0;width:100%;max-height:82vh;
    border-radius:18px 18px 0 0}
}
.helphead{display:flex;align-items:center;gap:10px;padding:13px 15px;
  border-bottom:1px solid var(--line);background:var(--panel2)}
.helphead b{font-family:'Fredoka','Inter',sans-serif;font-size:16px;flex:1;min-width:0}
.helpbody{padding:15px 17px 18px;overflow:auto;font-size:14px;line-height:1.6}
.helpbody h4{margin:16px 0 6px;font-size:13.5px;color:var(--acc2);
  letter-spacing:.04em;text-transform:uppercase;font-family:'Inter',sans-serif}
.helpbody h4:first-child{margin-top:0}
.helpbody p{margin:0 0 8px;color:var(--soft)}
.helpbody ul,.helpbody ol{margin:0 0 8px;padding-left:19px;color:var(--soft)}
.helpbody li{margin-bottom:5px}
.helpbody b{color:var(--ink)}
.helpbody kbd{font-family:'JetBrains Mono',monospace;font-size:11.5px;background:var(--sunken);
  border:1px solid var(--line2);border-bottom-width:2px;border-radius:5px;padding:1px 6px;color:var(--ink)}
.helprow{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}
.helprow .rbtn{flex:1 1 auto}

/* переключатель темы внутри помощи: три кнопки, светится текущая */
.themepick{display:flex;gap:6px;margin:2px 0 4px}
.themepick button{flex:1;border:1px solid var(--line2);background:var(--panel2);color:var(--soft);
  border-radius:10px;padding:9px 6px;font:600 13px/1.2 'Inter',sans-serif;cursor:pointer;transition:.15s}
.themepick button:hover{color:var(--ink);border-color:var(--acc)}
.themepick button.on{background:var(--acc);color:var(--onacc);border-color:transparent}

/* «?» рядом с заголовком раздела: тот же ответ, но не надо искать глазами
   кнопку в шапке. Ставится в правый верхний угол блока. */
.qm{flex:none;position:relative;width:26px;height:26px;padding:0;border-radius:50%;
  border:1px solid var(--line2);background:var(--panel2);color:var(--soft);
  font:700 13px/1 'Inter',sans-serif;cursor:pointer;transition:.15s}
/* ⚠️ Кружок 26px нарисован, а нажимается 44px. Это ровно та кнопка, за которую
   хватается растерявшийся ребёнок («что это за экран?»), и промахнуться по ней
   пальцем было легче всего на сайте. Невидимая площадка вокруг увеличивает
   цель до пальца, не раздувая саму точку в вёрстке заголовка. */
.qm::after{content:"";position:absolute;left:50%;top:50%;width:44px;height:44px;
  transform:translate(-50%,-50%)}
.qm:hover{background:var(--acc);color:var(--onacc);border-color:transparent}

/* ============================================================
   ПОИСК УРОКА
   Сто уроков лежат в пяти мирах по двадцать. Пока помнишь номер — всё
   хорошо, а «где было про словари» ищется только глазами по пяти экранам.
   Строка поиска стоит прямо в блоке «Уроки» и ищет по названию, подзаголовку
   и номеру; закрытые уроки показываются тоже — но видно, что они закрыты.
   ============================================================ */
.lsearch{display:flex;align-items:center;gap:9px;margin:0 0 14px}
.lsearch input{flex:1;min-width:0;box-sizing:border-box;border:1px solid var(--line2);
  border-radius:11px;background:var(--panel);color:var(--ink);padding:10px 13px;font:14px/1.4 'Inter',sans-serif}
.lsearch input:focus{outline:none;border-color:var(--acc)}
.lsearch input::placeholder{color:var(--faint)}
.lsfound{display:flex;flex-direction:column;gap:6px;margin:0 0 16px}
.lsrow{display:flex;align-items:center;gap:11px;text-align:left;width:100%;
  border:1px solid var(--line);border-radius:12px;background:var(--panel);
  color:inherit;font:inherit;padding:9px 13px;cursor:pointer;transition:.14s}
.lsrow:hover{border-color:var(--acc);background:var(--panel2)}
.lsrow .lsnum{flex:none;font:700 12px/1 'JetBrains Mono',monospace;color:var(--faint);min-width:30px}
.lsrow .lstitle{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600}
.lsrow .lssub{flex:none;font-size:12px;color:var(--faint)}
.lsrow.lock{opacity:var(--dim2);cursor:default}
.lsrow.lock:hover{border-color:var(--line);background:var(--panel)}
.lsnone{margin:0 0 16px;color:var(--faint);font-size:13.5px}
@media (max-width:620px){ .lsrow .lssub{display:none} }

/* ============================================================
   КНОПКА «НАВЕРХ»
   Экран урока и портфолио бывают в несколько экранов длиной, а кнопки
   «дальше» живут внизу — но «к списку уроков» и панель наверху. Кнопка
   появляется только когда прокрутили больше экрана, иначе она мусор.
   ============================================================ */
.toTop{position:fixed;right:16px;bottom:16px;z-index:55;width:42px;height:42px;
  border-radius:50%;border:1px solid var(--line2);background:var(--panel);color:var(--soft);
  font-size:16px;cursor:pointer;box-shadow:var(--sh);display:none;transition:.15s}
.toTop.show{display:block}
.toTop:hover{color:var(--ink);border-color:var(--acc)}
body.focus .toTop{display:none}
/* Прятать кнопку при печати отдельным правилом не надо: в @media print уже
   стоит `body>*{display:none}`, и оно закрывает всё, что лежит прямо в body,
   — включая эту кнопку и окно помощи. Дубль только сбивал бы с толку:
   казалось бы, что список надо пополнять при каждом новом элементе. */

/* ============================================================
   ЭКРАН «КАК ПОЛЬЗОВАТЬСЯ»
   Всплывающая помощь отвечает на «что тут прямо сейчас», а это — полная
   инструкция: устройство сайта, из чего состоит урок, откуда берутся
   звёзды, что делать, когда не получается, и отдельный кусок для родителя.
   ============================================================ */
.guide .card{margin-bottom:14px}
.guidesteps{counter-reset:g;list-style:none;margin:0;padding:0}
.guidesteps li{position:relative;padding:0 0 14px 42px;counter-increment:g}
.guidesteps li:last-child{padding-bottom:0}
.guidesteps li::before{content:counter(g);position:absolute;left:0;top:0;
  width:28px;height:28px;border-radius:50%;display:grid;place-items:center;
  background:var(--acc);color:var(--onacc);font:700 14px/1 'Inter',sans-serif}
.guidesteps b{display:block;margin-bottom:2px}
.guidesteps span{color:var(--soft);font-size:14px}
.keylist{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:8px;margin:0}
.keyrow{display:flex;align-items:baseline;gap:10px;font-size:13.5px;color:var(--soft)}
.keyrow kbd{flex:none;font-family:'JetBrains Mono',monospace;font-size:11.5px;background:var(--sunken);
  border:1px solid var(--line2);border-bottom-width:2px;border-radius:5px;padding:2px 7px;color:var(--ink)}
.iconlist{display:flex;flex-direction:column;gap:9px;margin:0}
.iconrow{display:flex;align-items:flex-start;gap:11px;font-size:14px}
.iconrow .ic{flex:none;width:34px;text-align:center;font-size:18px}
.iconrow span{color:var(--soft)}
.iconrow b{color:var(--ink)}


/* ---------- урок: объяснение слева, работа справа ----------
   Замер до правки (урок «Текст и числа», экран 1280×720): страница 2341px,
   редактор начинался на 1698-м — на 2,4 экрана ниже начала. Щёлкнув в
   редактор, ребёнок оказывался там, где не видно ни объяснения, ни текста
   задания, а под редактором только подсказки. После правки редактор
   начинается на 606-м и виден сразу, а задание стоит над ним и держится.

   Порог 1040px, а не 900: при 1040 правая колонка выходит примерно 540px, и
   редактор в ней ещё читается. Уже — колонка одна, и работает липкая
   полоска задания (.taskpin).

   Уроки с рисованием (их четыре) идут одной колонкой: у них рядом с
   редактором стоит холст, и на 540px эта пара не помещается. */
.lessongrid{display:block}
.lcol-read,.lcol-work{min-width:0}
@media (min-width:1040px){
  .lessongrid:not(.one){display:grid;grid-template-columns:minmax(0,46fr) minmax(0,54fr);
    gap:0 22px;align-items:start}
  .lessongrid:not(.one) .lcol-work{position:sticky;top:72px}
  /* колонки должны начинаться на одной высоте: слева первая карточка со
     своим margin-bottom, справа редактор без верхнего отступа */
  .lessongrid:not(.one) .lcol-work>#studio:first-child{margin-top:0}
  /* холста в этой колонке нет, а 540px на редактор и вывод рядом не хватит */
  .lessongrid:not(.one) .studio.split{grid-template-columns:1fr}
}

/* ---------- разбор примера под кодом ----------
   Замер: в Мире 1 у 55 карточек из 72 объяснение короче 150 знаков, в Мире 2 —
   у 69 из 81. То есть чем МЛАДШЕ ребёнок в курсе, тем меньше ему объясняли. */
.demonote{margin:0;padding:11px 14px;border-top:1px dashed var(--line2);
  font-size:13.5px;line-height:1.55;color:var(--soft);background:var(--sunken)}
.demonote b{color:var(--ink)}

/* ---------- шапка верстака: «здесь решаешь задачу» ----------
   Задание стоит в конце объяснения, а редактор — наверху справа. Без этой
   шапки правая колонка это код и кнопки без единого слова о том, что вообще
   надо сделать: фаундер так и сказал — «непонятно, как решить задачу справа».
   Читает ребёнок, поэтому заголовок написан действием, а не термином. */
.worktask{border:1px solid var(--line2);border-radius:var(--r);background:var(--goalbg);
  padding:12px 15px;margin-bottom:12px}
.wthead{font-size:15px;font-weight:700;color:var(--ink);margin-bottom:5px}
.wtmain{display:flex;align-items:baseline;gap:10px;width:100%;border:0;background:transparent;
  color:var(--soft);font:inherit;font-size:13.5px;text-align:left;cursor:pointer;padding:0}
.wttxt{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Раскрытый блок прячет однострочник (атрибутом hidden, из обработчика):
   иначе цель задания стоит на экране дважды подряд — сначала строкой, потом
   первым абзацем раскрытого текста. Так это и выглядело у фаундера на уроке 6. */
.wtchev{flex:none;font-size:12px;color:var(--acc2);font-weight:600;white-space:nowrap}
/* Свернуть надо чем-то: раньше стрелка на раскрытом блоке пряталась совсем,
   и обратной дороги не было. */
.worktask.open .wtmain{justify-content:flex-end}
.wtfull{margin-top:8px;font-size:13.5px;color:var(--soft)}
.wtfull[hidden]{display:none}
.wtfull p{margin:0}
.wtfull ul{margin:8px 0 0;padding-left:19px}
/* На узком экране колонка одна, и задание стоит прямо над редактором —
   вторая копия того же текста там только мешала бы. */
@media (max-width:1039px){ .worktask{display:none} }

/* ---------- липкая полоска задания (узкий экран) ---------- */
/* Отступ сверху НЕ константа: на телефоне шапка складывается в две строки, и
   полоска с зашитыми 59px уехала бы под неё — ровно на том устройстве, ради
   которого она и делалась. Высоту шапки в --toph пишет syncTopHeight(). */
.taskpin{position:sticky;top:var(--toph,60px);z-index:55;background:var(--topbg);backdrop-filter:blur(14px);
  border-bottom:1px solid var(--line2)}
.taskpin[hidden]{display:none}
.tprow{max-width:1080px;margin:0 auto;padding:7px 18px;display:flex;align-items:center;gap:10px}
.tpmain{flex:1;min-width:0;display:flex;align-items:center;gap:8px;border:0;background:transparent;
  color:var(--ink);font:inherit;font-size:13.5px;text-align:left;cursor:pointer;padding:0}
.tpem{flex:none}
.tptxt{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--soft)}
.tpchev{flex:none;color:var(--faint);transition:transform .15s}
.taskpin.open .tpchev{transform:rotate(180deg)}
.taskpin.open .tptxt{white-space:normal;overflow:visible}
.tpup{flex:none;border:1px solid var(--line2);background:var(--panel);color:var(--soft);
  border-radius:9px;padding:5px 10px;font-size:12.5px;font-weight:600;cursor:pointer;white-space:nowrap}
.tpup:hover{color:var(--ink);border-color:var(--acc)}
.tpfull{max-width:1080px;margin:0 auto;padding:0 18px 10px;font-size:13.5px;color:var(--soft)}
.tpfull[hidden]{display:none}
.tpfull ul{margin:6px 0 0;padding-left:19px}
@media (min-width:1040px){ .taskpin{display:none} }
@media print{ .taskpin{display:none} }

/* Кнопка «прочитать вслух» на карточке урока. float, а не абсолют: карточки
   разной высоты, и позиционирование поверх заголовка ломало бы длинные. */
.saybtn{float:right;margin:0 0 8px 12px;border:1px solid var(--line);background:var(--panel);
  color:var(--soft);border-radius:999px;padding:5px 11px;font-size:14px;line-height:1.2;cursor:pointer}
.saybtn:hover{color:var(--ink);border-color:var(--acc2)}
.saybtn:focus-visible{outline:2px solid var(--acc2);outline-offset:2px}

/* Время урока и строка «куда это ведёт». */
.lmin{color:var(--faint);font-size:12.5px;white-space:nowrap;margin-right:10px}
.lesson.locked .lmin,.lesson.soon .lmin{opacity:.55}
.tag.time{background:none;border:none;padding:0;color:var(--faint)}
.path{background:var(--panel2);border:1px solid var(--line);border-radius:var(--r);
  padding:12px 16px;margin:12px 0 4px;font-size:14.5px;line-height:1.6;color:var(--soft)}
.path b{color:var(--ink)}

/* «Спроси»: готовые вопросы вместо микрофона (см. app.js). Кнопки переносятся —
   на телефоне четыре вопроса в строку не помещаются. */
.card.ask .askrow{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.askans{margin-top:12px;padding:12px 14px;border-radius:var(--r);background:var(--sunken);
  border:1px solid var(--line);font-size:14.5px;line-height:1.6;color:var(--ink)}
.askans b{display:block;margin-bottom:6px;color:var(--acc)}

/* ===== занятие: полоса, план, карточки ===== */
.zanbar{height:10px;border-radius:99px;background:var(--sunken);border:1px solid var(--line);
  overflow:hidden;margin:10px 0 6px}
.zanbar i{display:block;height:100%;background:linear-gradient(90deg,var(--acc),var(--acc-lt));
  transition:width .3s ease}
.zanmeta{color:var(--soft);font-size:14px;margin:0 0 12px}
.zanplan{list-style:none;padding:0;margin:6px 0 0;display:grid;gap:8px}
.zanplan li{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:10px 12px;
  border:1px solid var(--line);border-radius:12px;background:var(--panel2);color:var(--soft)}
.zanplan li.done{border-color:var(--okline);background:var(--okbg);color:var(--okink)}
.zanplan li.cur{border-color:var(--acc);background:var(--panel);color:var(--ink)}
.zanplan li b{color:inherit}
.zanplan .zi{width:26px;text-align:center;font-size:18px}
.zancard.on{border-color:var(--acc)}
.zancard.done{border-color:var(--okline)}
.zanrep{margin:6px 0 0;padding-left:18px;display:grid;gap:6px;color:var(--soft);font-size:14px}
.zanrep li{line-height:1.5}

/* ---------- таблица «Пример работы программы» (каркас ОГЭ) ---------- */
.ogesample{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;margin-top:12px}
.ogesample div{border:1px solid var(--line2);border-radius:10px;padding:8px 11px;background:var(--panel)}
.ogesample b{display:block;font-size:12.5px;color:var(--soft);margin-bottom:5px}
.ogesample pre{margin:0;font-size:13px;line-height:1.5;white-space:pre-wrap}

/* ---------- «Ты и ИИ»: отличие от курсов про нейросети ---------- */
.aidiff{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px;margin-top:8px}
.aidiff div{border:1px solid var(--line);border-radius:var(--r);padding:10px 13px;background:var(--panel)}
.aidiff div:last-child{border-color:var(--okline);background:var(--okbg)}
/* Только ЗАГОЛОВОК колонки, а не любой <b> внутри: без «>» правило ловило
   выделение «принять работу» в тексте и выбрасывало его на отдельную строку. */
.aidiff > div > b{display:block;margin-bottom:4px;font-size:14px}
.aidiff span{font-size:13.5px;line-height:1.5;color:var(--soft)}

/* ---------- приёмка: нотация ---------- */
.specref{display:grid;gap:8px;margin-top:8px}
.specref div{display:flex;gap:12px;align-items:baseline;flex-wrap:wrap;font-size:13.5px}
.specref code{white-space:pre-wrap}
.specref span{color:var(--soft)}
.specin{width:100%;min-height:150px;font-family:'JetBrains Mono',monospace;font-size:13.5px;
  line-height:1.6;margin-bottom:10px}
.speclist{display:grid;gap:6px;margin-top:8px}
.specone{display:grid;grid-template-columns:auto 1fr;gap:4px 10px;align-items:baseline;
  font-size:13px;padding:7px 10px;border-radius:9px;border:1px solid var(--line);
  background:var(--panel)}
.specone code{grid-column:2}
.specone span{grid-column:2;color:var(--soft)}
.specone .specmark{grid-row:1 / span 2;font-weight:700}
.specone.ok{border-color:var(--okline)}
.specone.ok .specmark{color:var(--ok)}
/* ⚠️ Не прошедшая строка — жёлтая, а не красная: это не ошибка ребёнка,
   а найденное расхождение, ради которого приёмка и затевалась. */
.specone.bad .specmark{color:var(--warn)}

/* ---------- группа: рабочее место репетитора ---------- */
.grouplist{display:grid;gap:10px;margin-top:8px}
.grouprow{border:1px solid var(--line);border-radius:var(--r);padding:11px 13px;background:var(--panel)}
.grouprow.ok{border-color:var(--okline)}
.grphead{display:flex;justify-content:space-between;align-items:baseline;gap:10px;
  flex-wrap:wrap;font-size:14px}
/* ⚠️ Ни одной красной пометки: красный на экране репетитора читается как
   «поймали ребёнка», а мы никого не ловим. Тишина и трудный урок — жёлтым,
   ровный ход — зелёным. */
.trmarks li.quiet,.trmarks li.tough,.trmarks li.pred,.trmarks li.stuck{color:var(--warn)}
/* План и факт (корзина 3.5). ⚠️ «Отстаёт» — тем же жёлтым, что тишина, и ни в
   коем случае не красным: это расстояние до рамки, которую поставил взрослый,
   а не приговор ребёнку. «Впереди» и «по плану» — зелёным, и такого же
   размера: колонка, у которой заметна только плохая половина, и есть табель. */
.grpplan{margin:6px 0 0;font-size:13.5px;line-height:1.45;color:var(--soft)}
.grpplan.ontrack,.grpplan.ahead{color:var(--ok)}
.grpplan.behind{color:var(--warn)}
.grpplan.none{opacity:var(--dim2)}
/* Заметка взрослого над объяснением урока (корзина 3.7).
   ⚠️ Не «сообщение» и не пузырь чата: у продукта красная линия на болталку,
   и вид заметки не должен обещать ответа. Записка на полях — рамка слева,
   спокойный фон, никакой кнопки рядом. */
.lnote{margin:0 0 14px;padding:10px 13px;border-left:3px solid var(--acc);
  border-radius:0 12px 12px 0;background:var(--sunken)}
.lnote b{display:block;font-size:12.5px;font-weight:600;color:var(--faint);
  margin-bottom:4px}
.lnote p{margin:0;line-height:1.55}
.notelist{margin:8px 0 0;padding:0;list-style:none;display:grid;gap:10px}
.notelist li{border:1px solid var(--line);border-radius:12px;padding:9px 11px}
.notelist li p{margin:5px 0 7px;line-height:1.5}
.notelist li b{font-size:14px}
.notelist .nmk{margin:4px 0 0;padding-left:14px;font-size:13px;color:var(--soft)}
/* Пометки к строкам на экране урока: цитата строки моноширинным, фраза —
   обычным. Ребёнок должен узнать строку глазами, а не сверять номер. */
.lnmarks{margin:8px 0 0;padding:0;list-style:none;display:grid;gap:7px}
.lnmarks li{line-height:1.5}
.lnmarks .lnln{display:inline-block;font-size:12px;font-weight:700;color:var(--acc);
  margin-right:6px}
.lnmarks code{font-family:'JetBrains Mono',monospace;font-size:12.5px;
  background:var(--code);border-radius:5px;padding:1px 5px}
/* Заготовка урока у взрослого: строки-кнопки, по которым он тыкает. */
.mkpick{margin:6px 0 0;border:1px solid var(--line);border-radius:12px;
  background:var(--code);overflow:hidden;max-height:340px;overflow-y:auto}
.mkpick button{display:flex;gap:10px;width:100%;border:0;background:none;text-align:left;
  font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.6;
  padding:2px 10px;color:var(--codeink);cursor:pointer}
.mkpick button:hover{background:var(--sunken)}
.mkpick button.on{background:var(--sunken);box-shadow:inset 3px 0 0 var(--acc)}
.mkpick button i{font-style:normal;color:var(--gutink);min-width:20px;text-align:right;
  flex:none;user-select:none}
.mkpick button span{white-space:pre-wrap;word-break:break-word}

/* Ступень лестницы выхода — внутри сообщения о неудаче, под ним.
   ⚠️ Рамка сверху, а не своя коробка: это продолжение того же ответа урока,
   а не отдельная плашка «а вот и надзиратель». Кнопка обычная, «check», —
   ступень предлагает ход, а не сигналит тревогу. */
.stkstep{margin-top:10px;padding-top:10px;border-top:1px dashed currentColor;
  display:flex;flex-direction:column;align-items:flex-start;gap:7px;line-height:1.55}
.stkstep b{display:block}
.stkstep .rbtn{margin-top:2px}
.stknote{font-size:12.5px;opacity:var(--dim2)}

/* Затык в недельной карточке. ⚠️ Жёлтым, как «тяжело далось», а не красным:
   красный на экране взрослого читается как «с ребёнком что-то не так», а тут
   сказано только, что урок не взят и курс дальше не пускает. */
.wrstuck{margin:10px 0 0;padding:10px 12px;border-radius:12px;
  background:var(--warnbg);border:1px solid var(--warnline)}
.wrstuck b{display:block;margin-bottom:4px;color:var(--warn)}
.wrstuck p{margin:0 0 6px;font-size:13.5px;line-height:1.55}
.wrstuck p:last-child{margin-bottom:0}
.planfact{margin:6px 0 0;line-height:1.5}
.planfact.ontrack b,.planfact.ahead b{color:var(--ok)}
.planfact.behind b{color:var(--warn)}

/* ---------- витрина «что создают ученики» ---------- */
.showout{margin:8px 0 0;padding:9px 11px;border-radius:10px;background:var(--sunken);
  border:1px solid var(--line);overflow-x:auto;font-size:12.5px;line-height:1.55;
  white-space:pre;color:var(--ink)}
.showout[hidden]{display:none}
.drawstrip{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px;margin-top:10px}
.drawcell{display:grid;gap:5px}
.drawcell canvas{width:100%;border-radius:10px;border:1px solid var(--line)}

/* Строка «твою задачу решили» в списке своих заданий: это хорошая новость,
   и цвет у неё соответствующий. */
.solvedline{color:var(--ok);font-weight:600}

/* ---------- мастерская: полка деталей ---------- */
.shelf{display:grid;gap:12px;margin-top:10px}
.partcard{border:1px solid var(--line);border-radius:var(--r);padding:11px 13px;background:var(--panel)}
.parthead{display:flex;justify-content:space-between;align-items:baseline;gap:10px;flex-wrap:wrap;
  font-size:14px;margin-bottom:6px}
.partcard pre{margin:0;overflow-x:auto;font-size:12.5px;line-height:1.5}
.partbar{display:flex;gap:8px;flex-wrap:wrap;margin-top:9px}
.shopcard{margin-bottom:14px}

/* ---------- запись авторства («Как шла работа») ---------- */
/* Пометки красим тремя цветами, и ни один из них не красный: красный на
   экране взрослого читается как «поймали», а мы ничего не ловим. Сильная
   пометка — жёлтая, «написано руками» — зелёная, служебное — серое. */
.trrules,.trsum{margin:6px 0 0;padding-left:18px;display:grid;gap:8px;color:var(--soft);font-size:14px}
.trrules li,.trsum li{line-height:1.5}
.trlist{display:grid;gap:10px;margin-top:8px}
.trrow{border:1px solid var(--line);border-radius:var(--r);padding:10px 13px;background:var(--panel)}
.trrow.ok{border-color:var(--okline)}
.trhead{display:flex;justify-content:space-between;align-items:baseline;gap:10px;flex-wrap:wrap;font-size:14px}
.trmarks{margin:6px 0 0;padding-left:2px;list-style:none;display:grid;gap:4px;font-size:13.5px}
.trmarks li{line-height:1.45;color:var(--soft)}
.trmarks li.ready,.trmarks li.ahead{color:var(--warn)}
.trmarks li.hand{color:var(--ok)}
.trnum{margin-top:6px;font-size:12px;color:var(--faint)}
.zanwas{font-size:16px;margin:0 0 6px}
.ptcard .ptrow{display:flex;gap:10px;align-items:center;justify-content:space-between;
  flex-wrap:wrap;padding:9px 0;border-bottom:1px solid var(--line)}
.ptcard .ptrow:last-of-type{border-bottom:none}
.asktext{font-size:17px;line-height:1.5}

/* ===== карта активности: день × час ===== */
.heat{display:grid;gap:3px;margin:8px 0 6px;overflow-x:auto}
.heatrow,.heathead{display:flex;align-items:center;gap:8px}
.heat .hd{width:52px;flex:none;font-size:12px;color:var(--faint);font-variant-numeric:tabular-nums}
.heat .hcells{display:grid;grid-template-columns:repeat(24,1fr);gap:3px;flex:1;min-width:300px}
.heathead .hcells{color:var(--faint);font-size:11px}
.heathead .hcells b{grid-column:span 6;font-weight:600}
.heat i{display:block;height:13px;border-radius:3px;background:var(--sunken);border:1px solid var(--line)}
.heat i.hl1{background:var(--glow1);border-color:var(--line2)}
.heat i.hl2{background:var(--acc-lt);opacity:.45;border-color:transparent}
.heat i.hl3{background:var(--acc-lt);opacity:.72;border-color:transparent}
.heat i.hl4{background:var(--acc);border-color:transparent}
.heatscale{display:flex;align-items:center;gap:4px;font-size:12px;color:var(--faint)}
.heatscale i{display:block;width:13px;height:13px;border-radius:3px;background:var(--sunken);
  border:1px solid var(--line)}
.heatscale i.hl1{background:var(--glow1);border-color:var(--line2)}
.heatscale i.hl2{background:var(--acc-lt);opacity:.45;border-color:transparent}
.heatscale i.hl3{background:var(--acc-lt);opacity:.72;border-color:transparent}
.heatscale i.hl4{background:var(--acc);border-color:transparent}

/* ===== кабинет взрослого ===== */
.warnline{background:var(--warnbg);border:1px solid var(--warnline);color:var(--warnink);
  border-radius:12px;padding:10px 12px;font-size:14px;line-height:1.5;margin:8px 0}
.brlist{list-style:none;padding:0;margin:6px 0;display:grid;gap:6px}
.brlist li{display:flex;align-items:center;gap:10px;font-size:14px;color:var(--soft)}
/* Календарь занятий. ⚠️ Колонки узкие (130px) и тянутся сами: сорок дат
   простынёй по 210px занимали пол-экрана — фаундер назвал это безобразием
   12.09.2026. Дата это семь знаков, и колонка под неё нужна семизначная. */
.planlist{list-style:none;padding:0;margin:8px 0;display:grid;gap:6px;
  grid-template-columns:repeat(auto-fill,minmax(130px,1fr))}
.planlist li{font-size:13px;color:var(--soft);background:var(--panel2);
  border:1px solid var(--line2);border-radius:10px;padding:6px 9px}
.plandet{margin:8px 0}
.plandet>summary{cursor:pointer;font-size:14px;color:var(--acc);
  list-style:none;display:inline-flex;align-items:center;gap:6px}
.plandet>summary::-webkit-details-marker{display:none}
.plandet>summary::before{content:"▸";transition:.15s}
.plandet[open]>summary::before{transform:rotate(90deg)}
.planline{margin:6px 0;font-size:15px}
/* Одна строка, отвечающая за весь экран настроек: что настроено сейчас. */
.zansum{margin:2px 0 10px;font-size:17px;font-weight:650;color:var(--ink);
  background:var(--panel2);border:1px solid var(--line2);border-left:4px solid var(--acc);
  border-radius:12px;padding:11px 14px}
.zansum.none{font-weight:500;color:var(--soft);border-left-color:var(--line2)}
/* выбор роли на общем компьютере */
.rolegrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px;margin:18px 0}
.rolecard{display:flex;flex-direction:column;align-items:flex-start;gap:6px;text-align:left;
  border:1px solid var(--line2);background:var(--panel);border-radius:16px;padding:20px 18px;cursor:pointer;
  transition:.15s;font:inherit;color:inherit}
.rolecard:hover{border-color:var(--acc);transform:translateY(-2px);background:var(--panel2)}
.rolecard .roleico{font-size:34px;line-height:1}
.rolecard b{font-size:18px;margin-top:4px}
.rolecard .dim{font-size:13px}
/* список учеников в кабинете взрослого */
.kidlist{display:grid;gap:10px;margin:14px 0}
.kidcard{border:1px solid var(--line);border-radius:14px;padding:14px 16px;background:var(--panel)}
.kidmain{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin-bottom:10px}
.kidmain b{font-size:18px}
.kidcode{font-family:'JetBrains Mono',ui-monospace,monospace;font-size:12.5px;color:var(--faint)}
.kidacts{display:flex;gap:8px;flex-wrap:wrap}
.prow{display:flex;gap:12px;flex-wrap:wrap;margin:8px 0}
.madelink{border:1px solid var(--okline);background:var(--okbg);border-radius:12px;
  padding:10px 12px;margin:10px 0;font-size:14px;line-height:1.5}
.brk{word-break:break-all;font-family:'JetBrains Mono',monospace;font-size:12px}
.adrep .zanrep{padding-left:20px}
.lblin{background:var(--sunken);border:1px solid var(--line2);border-radius:8px;padding:5px 8px;
  color:var(--ink);font-size:13px;min-width:150px}
.lblin:focus{outline:none;border-color:var(--acc)}
.zanplan li.cut{border-style:dashed;opacity:.75}
.zanask{border-color:var(--acc)}
/* выбор задач домашки в кабинете взрослого */
.hwpick{display:grid;gap:8px;margin:12px 0}
.hwitem{display:flex;align-items:flex-start;gap:10px;border:1px solid var(--line);
  border-radius:11px;padding:9px 12px;background:var(--sunken);font-size:14px;
  line-height:1.45;cursor:pointer}
.hwitem:hover{border-color:var(--acc)}
.hwitem input{margin-top:3px;flex:none}
.hwitem .dim{display:block;font-size:12.5px}
.hwitem.off{opacity:.55;cursor:default}
.hwitem.off:hover{border-color:var(--line)}
/* отчёт родителю текстом и вопросы к занятию */
.reptext{white-space:pre-wrap;background:var(--sunken);border:1px solid var(--line2);
  border-radius:11px;padding:12px 14px;font-size:14px;line-height:1.55;
  font-family:inherit;margin:10px 0;overflow-x:auto}
.askqs{display:grid;gap:10px;margin:12px 0;padding-left:20px}
.askqs li{line-height:1.5}
.askqs li .dim{display:block;font-size:13px}
/* возвращение после паузы и «в следующий раз» */
.comeback{border-color:var(--okline);background:var(--okbg)}
.nexttime h3{margin-bottom:6px}
/* игра по ссылке: сначала играют, код спрятан до «Заглянуть в код» */
.studio.plonly .editorbox .ehead,
.studio.plonly .editorbox .edit-area,
.studio.plonly .editorbox .keybar{display:none}
.studio.plonly .editorbox{background:transparent;border:none;box-shadow:none;padding:0}
.gamecard.locked{opacity:.55;cursor:default}
/* присутствие и живое занятие */
.presence{border:1px solid var(--okline);background:var(--okbg);color:var(--okink);
  border-radius:11px;padding:9px 12px;margin:0 0 12px;font-size:14px}
.presence.live{border-color:#e2a1a1;background:rgba(200,60,60,.08);color:inherit;
  display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.livebar{position:fixed;left:50%;bottom:14px;transform:translateX(-50%);z-index:80;
  display:flex;align-items:center;gap:14px;background:var(--panel);color:var(--ink);
  border:2px solid #d66;border-radius:14px;padding:10px 16px;font-size:14px;
  box-shadow:0 6px 24px rgba(0,0,0,.25);max-width:92vw}
.grlive{font-size:11px}
.presence.day{border-color:var(--line);background:var(--sunken);color:var(--soft);margin-top:-6px}

/* ================= планшет: открыта виртуальная клавиатура =================
   Класс kb вешает kbApply() по сжатию visualViewport. Пока он висит, на
   экране не должно быть ничего липкого и плавающего: липкая колонка и
   полоска задания дёргаются при каждом скролле, а плавающие кнопки на iOS
   всплывают над клавиатурой посреди экрана. */
.kb .lessongrid:not(.one) .lcol-work{position:static}
.kb .taskpin{display:none}
.kb .toTop,.kb .toast,.kb .livebar{display:none}
/* Автопрокрутка браузера к сфокусированному полю метит в край экрана:
   отступы говорят ей не прятать поле под шапку и не прижимать к клавиатуре. */
html{scroll-padding-top:84px;scroll-padding-bottom:140px}

/* ================= вывеска: первый экран для гостя =================
   Единственный экран сайта, который читают, а не проходят, — и это диктует
   вёрстку. Строка здесь длиннее обычной (720px против сплошной колонки):
   на витрине читают абзацами, а не сканируют список уроков.

   Оформление переписано 06.09.2026 после разбора конкурентов
   (docs/vyveska.md § 7). Коротко, что оттуда взято и что нет:

   • У всех российских школ на первом экране ФОТОГРАФИЯ ребёнка за ноутбуком
     (Алгоритмика, Пиксель, Айтигенио). Снимать нам некого, покупать сток —
     значит выглядеть как все. Поэтому первый экран показывает не ребёнка,
     а САМ ПРОДУКТ: живое окно редактора, где код действительно запускается
     нашим движком. Ни один конкурент так не может — у них обучение живёт за
     логином, у нас оно и есть страница.
   • У Codédex (лучший по картинке из всех) первый экран — это МИР, в который
     заходишь. Метафора совпадает с нашей («квест», пять миров, боссы),
     поэтому программа курса нарисована дорогой с узлами, а не серым списком.
   • Чего не берём: 3D-глянец, всплывающие окна с «оставьте телефон» и
     обратный отсчёт. Продукт продаёт понятность, и вывеска обязана быть
     такой же.

   ⚠️ Ни одного своего цвета в правилах: всё на переменных темы. Вывеска
   обязана одинаково жить в светлой и тёмной, иначе на первом же экране сайт
   выглядит чужим. Переменные, которые нужны только здесь, объявлены ниже
   двумя блоками — светлым и тёмным, — и больше нигде не используются. */
:root{
  /* Пять миров — пять цветов. Нужны затем, что пятёрка одинаковых серых
     карточек не читается как ПУТЬ: глазу не за что зацепиться, и «Мир 3»
     от «Мира 4» отличается только цифрой. Оттенки взяты из уже имеющейся
     палитры подсветки кода, чтобы вывеска не завела на сайте второй набор
     цветов. */
  --w1:#0e7a55; --w2:#9a6a00; --w3:#1f56c8; --w4:#6d3fd6; --w5:#b8365f;
  --w1bg:#e4f4ee; --w2bg:#faf0dc; --w3bg:#e6ecfd; --w4bg:#eee8fd; --w5bg:#fce9ef;
  /* Свечение первого экрана. Три пятна, а не градиент в две точки: градиент
     на широком мониторе виден полосой, пятна — нет. */
  --lg1:rgba(124,92,255,.26); --lg2:rgba(0,168,140,.20); --lg3:rgba(255,168,64,.16);
  --lgrid:rgba(26,31,61,.055);
  --dwbar:#eef1fa;
}
:root[data-theme="dark"]{
  --w1:#4fd8a0; --w2:#ffc964; --w3:#82aaff; --w4:#b79bff; --w5:#ff87ac;
  --w1bg:rgba(79,216,160,.11); --w2bg:rgba(255,201,100,.11); --w3bg:rgba(130,170,255,.11);
  --w4bg:rgba(183,155,255,.11); --w5bg:rgba(255,135,172,.11);
  --lg1:rgba(124,92,255,.30); --lg2:rgba(0,224,184,.14); --lg3:rgba(255,168,64,.10);
  --lgrid:rgba(255,255,255,.045);
  --dwbar:#101632;
}
.land{display:flex;flex-direction:column;gap:34px}

/* ---------- появление при прокрутке ----------
   Не украшение: на длинной странице сдвиг на десяток пикселей говорит глазу
   «сюда пришёл новый блок» и разбивает восемь разделов подряд на порции.
   Класс вешает наблюдатель в js/app.js; без JS всё видно сразу, потому что
   начальное состояние ставится ТОЛЬКО вместе с классом .rv. */
.rv{opacity:0;transform:translateY(14px)}
.rv.in{opacity:1;transform:none;transition:opacity .5s ease,transform .5s cubic-bezier(.2,.7,.3,1)}
@media (prefers-reduced-motion:reduce){
  .rv,.rv.in{opacity:1;transform:none;transition:none}
}

/* ---------- первый экран ---------- */
.landhero{position:relative;overflow:hidden;border:1px solid var(--line);
  border-radius:26px;background:var(--panel);box-shadow:var(--shbig);
  padding:44px 40px 40px}
/* Фон рисуется отдельным слоем, а не фоном самой карточки: слоёв три
   (сетка + три пятна), и в одном свойстве background они дрались бы за
   background-size друг с другом. aria-hidden стоит в разметке. */
.lhaur{position:absolute;inset:0;pointer-events:none;
  background:
    radial-gradient(600px 360px at 10% -12%, var(--lg1), transparent 72%),
    radial-gradient(560px 340px at 94% 6%,   var(--lg2), transparent 70%),
    radial-gradient(500px 320px at 58% 112%, var(--lg3), transparent 72%)}
/* Сетка лежит ОТДЕЛЬНЫМ слоем поверх пятен и гасится маской к краям: без
   маски карточка выглядит миллиметровкой, а если гасить не маской, а
   накрывающей плашкой цвета панели, — вместе с сеткой гаснут и сами пятна,
   и первый экран становится белым листом. */
.lhaur::after{content:"";position:absolute;inset:0;
  background:
    linear-gradient(0deg,var(--lgrid) 1px,transparent 1px) 0 0/100% 34px,
    linear-gradient(90deg,var(--lgrid) 1px,transparent 1px) 0 0/34px 100%;
  -webkit-mask-image:radial-gradient(90% 80% at 50% 42%,#000 20%,transparent 78%);
  mask-image:radial-gradient(90% 80% at 50% 42%,#000 20%,transparent 78%)}
/* ⚠️ Колонки выравниваются ПО ВЕРХУ, а не по центру. Раньше стояло center, и
   пока обе половины были примерно одной высоты, это сходило с рук. С 1.94.0
   справа рисунок, окно стало заметно выше — и заголовок «Информатика без
   репетитора» уехал вниз от верхнего края окна почти на двести пикселей.
   Находка фаундера 07.09.2026. Первый экран читают сверху вниз, и обе
   половины обязаны начинаться на одной линии. */
.lhin{position:relative;display:grid;grid-template-columns:minmax(0,1.12fr) minmax(0,1fr);
  gap:34px;align-items:start}
.lhtext{min-width:0}
/* Плашка над заголовком. Точка перед текстом — не декор: она держит взгляд
   на строке, набранной капителью, которая иначе читается как подпись. */
.landkick{display:inline-flex;align-items:center;gap:8px;
  font-size:11.5px;letter-spacing:.08em;text-transform:uppercase;
  color:var(--acc2);font-weight:700;margin-bottom:14px;
  background:var(--panel2);border:1px solid var(--line);border-radius:999px;
  padding:6px 13px 6px 10px}
.landkick i{width:7px;height:7px;border-radius:50%;background:var(--acc2);flex:none}
.landhero h1{margin:0 0 14px;font-size:52px;line-height:1.04;letter-spacing:-.02em}
/* Подчёркивание под ключевыми словами. Рисуется фоном, а не border-bottom:
   нужна толстая мягкая полоса ПОД буквами, не задевающая хвосты «р» и «у». */
.hlite{position:relative;white-space:nowrap;
  background:linear-gradient(var(--acc-lt),var(--acc-lt)) 0 96%/100% .14em no-repeat}
:root[data-theme="dark"] .hlite{background-image:linear-gradient(var(--acc-lt),var(--acc-lt))}
.landlede{margin:0;font-size:18px;line-height:1.55;color:var(--soft)}
.landcta{display:flex;flex-wrap:wrap;gap:12px;margin:24px 0 0}
/* Главная кнопка на вывеске светится. Единственное место на сайте, где это
   уместно: у гостя на экране два десятка карточек и одно действие. */
.landcta .bigbtn:first-child{box-shadow:0 10px 30px -10px var(--acc)}
.landsub{margin:16px 0 0;font-size:13.5px;color:var(--faint)}
/* Четыре факта строкой. Это ответ на возражения, которые родитель проговаривает
   про себя, пока читает заголовок: «опять что-то ставить», «опять интернет»,
   «опять телефон оставлять». Отвечать на них абзацем поздно — он до абзаца
   не дойдёт. */
.landjump{margin:18px 0 0;font-size:13.5px;color:var(--faint)}
.linkjump{background:none;border:none;padding:0;font:inherit;font-size:13.5px;
  font-weight:600;color:var(--accink);cursor:pointer;text-decoration:underline;
  text-underline-offset:3px;text-decoration-thickness:1px}
.linkjump:hover{text-decoration-thickness:2px}
.landtrust{list-style:none;margin:16px 0 0;padding:0;display:flex;flex-wrap:wrap;gap:8px}
.landtrust li{display:flex;align-items:center;gap:7px;font-size:13px;color:var(--soft);
  background:var(--panel2);border:1px solid var(--line);border-radius:11px;padding:7px 12px}
.landtrust b{font-weight:600;color:var(--ink)}

/* ---------- вход и регистрация на первом экране ----------
   Одно поле на два дела: имя заводит профиль, код открывает уже заведённый.
   ⚠️ Размер шрифта в поле 16px и на широком экране тоже: меньше — и Safari
   на телефоне сам увеличивает страницу при касании поля, а первый экран
   уезжает вбок. */
/* ⚠️ Потолок стоит на РЯДУ с полем, а не на всём блоке: с 1.138.0 в блоке есть
   строка текста под кнопкой, и потолок блока рвал её на две при свободной
   колонке справа (правило полной ширины, RAZVITIE § 4.13). */
.ldauth{margin:24px 0 0}
.ldauthrow{display:flex;flex-wrap:wrap;gap:12px;max-width:520px}
.ldauthrow input{flex:1 1 200px;min-width:0;background:var(--panel);
  border:1px solid var(--line2);border-radius:12px;padding:13px 16px;
  color:var(--ink);font-size:16px;font-family:'Inter',sans-serif}
.ldauthrow input::placeholder{color:var(--faint)}
.ldauthrow input:focus{outline:none;border-color:var(--acc)}
/* Свечение — то же, что было у главной кнопки вывески: действие на первом
   экране по-прежнему одно, просто теперь у него есть поле. */
.ldauthrow .bigbtn{box-shadow:0 10px 30px -10px var(--acc)}
.ldalt{margin:12px 0 0;font-size:13.5px;color:var(--faint)}

/* ---------- живое окно редактора на первом экране ----------
   Главный аргумент вывески и единственная её «картинка». Никакого скриншота:
   внутри работает тот же движок, что и в уроке, поэтому окно не может
   разойтись с продуктом — если сломается движок, сломается и витрина. */
.lhdemo{min-width:0}
.demowin{margin:0;border:1px solid var(--line2);border-radius:18px;overflow:hidden;
  background:var(--code);box-shadow:var(--shbig)}
/* ⚠️ flex-wrap обязателен. Без него подпись справа (.dwtag) с nowrap не
   помещалась в узкую колонку и обрезалась окном по overflow:hidden —
   посередине слова: «код можно править пр». Находка фаундера 07.09.2026.
   Теперь строка переносится, и фраза остаётся целой. */
.dwhead{display:flex;flex-wrap:wrap;align-items:center;gap:4px 10px;padding:10px 14px;
  background:var(--dwbar);border-bottom:1px solid var(--line);font-size:12.5px;color:var(--soft)}
.dwdots{display:flex;gap:5px;flex:none}
.dwdots i{width:9px;height:9px;border-radius:50%;background:var(--dot)}
.dwhead b{color:var(--ink);font-size:12.5px;white-space:nowrap}
.dwhead .dwtag{margin-left:auto;color:var(--acc2);font-weight:600;
  white-space:normal;min-width:0}
/* Код с колонкой номеров — ровно как в редакторе урока. Это не украшение:
   родитель, увидевший на вывеске то же окно, что потом откроет ребёнок,
   узнаёт его и не думает, что ему показали рекламный макет. */
.dwcode{display:flex;font-family:'JetBrains Mono',monospace;font-size:13.5px;line-height:1.65}
.dwnums{flex:none;padding:14px 10px;background:var(--gut);color:var(--gutink);
  text-align:right;user-select:none;white-space:pre;font-size:12.5px;line-height:1.65}
.dwcode pre{margin:0;padding:14px 16px;overflow-x:auto;flex:1;min-width:0;color:var(--codeink)}
/* Живой редактор внутри окна вывески. Своей рамки и своей «шапки» с точками
   ему тут не нужно: рамку и точки даёт само окно (.demowin, .dwhead), а два
   заголовка подряд читались бы как две разные штуки. */
.dwed{border:none;border-radius:0;background:var(--code)}
.dwed .ehead{display:none}
/* ⚠️ Колонка номеров на вывеске СПРЯТАНА, и это не косметика. Редактор
   выравнивает номер с перенесённой строкой, проставляя каждому номеру
   вычисленную высоту; расчёт опирается на замер шрифта в самом редакторе и
   вне экрана урока даёт чушь — номерам доставались высоты в 900 и 1000
   пикселей, и окно демо растягивалось на две тысячи. Жалоба фаундера
   07.09.2026: «на мобильной версии экран убегает вниз на много слайдов».
   Номера тут и не нужны: это шесть строк примера, а не программа урока. */
.dwed .gutter{display:none}
/* ⚠️ И панель символов тоже. Она заведена для РЕБЁНКА, который пишет код на
   планшете, и там полезна. На вывеске она занимает три ряда — четверть
   первого экрана телефона — и отодвигает вниз рисунок, ради которого сюда и
   пришли. А посетителю она не нужна: единственное, что он здесь меняет, —
   число, и цифры есть на любой телефонной клавиатуре. */
.dwed .keybar{display:none}
.dwed .edit-area{border:none;border-radius:0}
.dwed .runbar{display:none}
.dwed .edit-scroll{min-height:150px}

.dwbar{display:flex;flex-wrap:wrap;gap:8px;align-items:center;padding:11px 14px;
  background:var(--dwbar);border-top:1px solid var(--line)}
.dwbtn{border:1px solid var(--line2);background:var(--panel);color:var(--ink);
  border-radius:10px;padding:7px 13px;font:inherit;font-size:13px;font-weight:600;
  cursor:pointer;transition:.15s}
.dwbtn:hover{border-color:var(--acc);color:var(--accink)}
.dwbtn.go{background:var(--acc);border-color:transparent;color:var(--onacc)}
.dwbtn.go:hover{background:var(--acc-lt);color:var(--onacc)}
.dwhint{margin-left:auto;font-size:12px;color:var(--faint)}
/* Подпись без кнопки рядом: прижимать её вправо не к чему. */
.dwhint.own{margin-left:0;flex:1;min-width:220px}
/* Вспышка «пересчитал»: единственный знак, который виден, даже если
   изменившаяся строка вывода осталась ниже края панели. */
@keyframes ranewflash{ from{background:rgba(0,224,184,.22)} to{background:var(--res)} }
.ldout.ranew{animation:ranewflash .65s ease-out}
/* Число в коде, которое можно поменять. Выглядит как число (тот же цвет, тот
   же моноширинный шрифт), а что его можно трогать — говорит пунктир снизу.
   Кнопкой не притворяется: это по-прежнему код, просто живой. */
.numin{font:inherit;font-family:inherit;font-size:inherit;line-height:inherit;
  color:var(--n);background:none;border:none;padding:0;margin:0;
  border-bottom:1px dashed currentColor;text-align:center;min-width:1.1em;
  border-radius:0;-moz-appearance:textfield}
.numin{background:rgba(127,127,127,.10)}
.numin:hover{background:rgba(127,127,127,.22)}
.numin:focus{outline:2px solid var(--acc2);outline-offset:1px;background:rgba(127,127,127,.14)}
/* ⚠️ На телефоне в это поле не попасть пальцем. Замер 07.09.2026 на экране
   375: самое узкое поле — 15×23 пикселя, площадь 345. Мы приглашаем «поменяй
   число», а нажать некуда.
   Растёт ТОЛЬКО ширина, и это не лень: высота строки кода 22 пикселя, поле
   уже 23 — стоит добавить вертикальные отступы, и поля соседних строк
   начинают наезжать друг на друга (проверено: четыре пары). Тап в полосе
   наложения уходит не в то поле, а это хуже мелкой цели.
   background-clip:content-box держит серую заливку на самом числе, чтобы
   поле не превращалось в широкую плашку посреди кода. */
@media (max-width:640px){
  .numin{min-width:2.4em;padding:0 7px;background-clip:content-box}
}
/* Окно вывода. Высота задана снизу, а не сверху: без min-height окно
   подпрыгивает на высоту шести строк в тот момент, когда на него смотрят. */
/* ⚠️ max-height обязателен, и это не косметика. Код в окне правит ПОСЕТИТЕЛЬ,
   и мы сами зовём его менять числа. Фаундер ввёл 1700 звёзд — программа
   честно напечатала 1700 строк, и страница уехала на километр вниз: вывеска
   превратилась в простыню, из которой не видно ничего. Ограничение сверху
   плюс своя прокрутка держат страницу целой при ЛЮБОМ коде, который посетитель
   сюда напишет, а не только при нашем примере. */
.dwout{padding:14px 16px;min-height:132px;max-height:340px;overflow:auto;
  background:var(--res);
  border-top:1px solid var(--line);font-family:'JetBrains Mono',monospace;
  font-size:13.5px;line-height:1.6;color:var(--outink);white-space:pre-wrap;
  word-break:break-word}
/* Холст рисунка. Ширину меряет сам drawTurtle по clientWidth, высоту ставит
   по ней же — поэтому здесь только ширина. */
.dwout .dwcanvas{display:block;width:100%;border-radius:10px}
.dwout .dwtext{margin:10px 0 0;font-family:'JetBrains Mono',monospace;
  font-size:13px;line-height:1.6;white-space:pre-wrap}
.dwout .dwwait{color:var(--faint);font-family:'Inter',sans-serif;font-size:13.5px}
.dwout .dwcaret{display:inline-block;width:8px;height:16px;vertical-align:-3px;
  background:var(--acc);animation:dwblink 1s steps(1) infinite}
@keyframes dwblink{50%{opacity:0}}
/* Плашка ошибки — та же, что видит ребёнок в уроке (класс .msg.bad там же). */
.dwerr{border:1px solid var(--badline);background:var(--badbg);color:var(--badink);
  border-radius:12px;padding:10px 13px;font-family:'Inter',sans-serif;font-size:13.5px;
  line-height:1.5;white-space:normal}
.dwerr b{display:block;color:var(--bad);margin-bottom:2px}
.dwnote{margin:12px 2px 0;font-size:13px;color:var(--faint);line-height:1.5}

/* ---------- полоса чисел ----------
   Восемь чисел, и все восемь — про объём. Раньше они стояли восемью
   одинаковыми карточками, то есть восемью прямоугольниками с рамками:
   такое читается как сетка ссылок, а не как «вот сколько тут всего».
   Теперь это одна полоса с волосяными разделителями. */
.landnums{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:1px;
  border:1px solid var(--line);border-radius:20px;background:var(--line);
  overflow:hidden;box-shadow:var(--sh)}
.landnum{padding:18px 20px;display:flex;flex-direction:column;gap:1px;background:var(--panel)}
.landnum b{font-family:'Fredoka','Inter',sans-serif;font-size:34px;line-height:1.05;
  color:var(--acc);letter-spacing:-.01em}
.landnum span{font-size:14px;font-weight:600}
.landnum i{font-style:normal;font-size:12.5px;color:var(--faint);line-height:1.4;margin-top:4px}
/* Числа живут ВНУТРИ первого экрана, в левой колонке: без них колонка
   кончалась на четыреста пикселей раньше правой, и под кнопками висела дыра.
   Здесь их две в ряд, а не четыре — колонка вдвое уже страницы. */
.lhtext .landnums{grid-template-columns:repeat(2,minmax(0,1fr));margin-top:16px;
  box-shadow:none;background:var(--line)}
/* ⚠️ Отступы и кегль здесь меньше, чем у полосы во всю ширину, и это ЗАМЕР,
   а не вкус: колонки первого экрана обязаны кончаться на одной высоте.
   С прежними числа перевешивали окно с рисунком на 126 px. */
.lhtext .landnum{padding:11px 14px}
.lhtext .landnum b{font-size:27px}
.lhtext .landnum i{margin-top:2px}

/* ---------- заголовки разделов ----------
   Надпись-указатель над заголовком отвечает на «что это за кусок страницы»
   раньше, чем человек прочтёт сам заголовок. На странице восемь разделов —
   без указателей они сливаются в один длинный текст. */
.landsect{scroll-margin-top:90px}
.seckick{display:block;font-size:11.5px;letter-spacing:.09em;text-transform:uppercase;
  color:var(--acc2);font-weight:700;margin-bottom:7px}
.landsect h2{margin:0 0 8px;font-size:27px;line-height:1.15;letter-spacing:-.015em}
.landsect .lede{margin:0;font-size:15.5px}
/* ⚠️⚠️ ПРАВИЛО ПОЛНОЙ ШИРИНЫ. Абзац занимает ВСЮ ширину своей колонки.
   Никаких max-width, режущих строку раньше края блока.
   История в три хода, каждый оплачен переделкой.
   06.09.2026: лид в одну колонку на 1080 px обрывался на 720 и читался как
   сломанная вёрстка — развели на две колонки, справа от узкой строки оказался
   не воздух, а заголовок.
   08.09.2026: после сокращения текстов лид стал в ОДНУ строку, и та же
   конструкция обернулась своей противоположностью — одинокая строка висела в
   правой половине на уровне второй строки заголовка, «как плевок, брошенный
   почти по центру» (слова фаундера). Свели обратно в одну колонку, а от
   растягивания поставили max-width:62ch.
   10.09.2026: max-width и оказался виноват. Колонка раздела — 1044 px, лид
   обрывался на 606 и переносился на вторую строку при том, что справа
   пустовала половина блока: текст «режется», а страница от этого ДЛИННЕЕ.
   Все шесть лидов вывески короче 110 знаков и в полную ширину встают в одну
   строку. Каппы сняты здесь и у .landlede, .landsub, .lwbody p.
   ⚠️ Вывод, который и есть правило: длину выбирает ТЕКСТ, а не колонка.
   Строка кажется длинной — сокращай текст, а не ширину. */
.secthead{margin-bottom:18px}
.secthead .sechl{min-width:0}
.secthead h2{margin:0}
.secthead .lede{margin:7px 0 0}

/* ---------- четыре шага урока ----------
   Дорожка с узлами, а не список: у шагов есть порядок, и линия между ними
   говорит это без слова «затем». */
.landsteps{list-style:none;counter-reset:ls;margin:0;padding:0;
  display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:0}
.landsteps li{counter-increment:ls;position:relative;padding:0 20px 0 0;background:none;border:none}
.landsteps li::before{content:counter(ls);display:flex;align-items:center;justify-content:center;
  width:40px;height:40px;border-radius:14px;background:var(--acc);color:var(--onacc);
  font-family:'Fredoka','Inter',sans-serif;font-size:20px;margin-bottom:12px;
  box-shadow:0 8px 20px -10px var(--acc);position:relative;z-index:1}
/* Линия идёт от узла вправо и обрывается у последнего: рисуем её на самом
   узле, а у последнего гасим. */
.landsteps li::after{content:"";position:absolute;left:40px;top:19px;right:0;height:2px;
  background:linear-gradient(90deg,var(--line2),var(--line))}
.landsteps li:last-child::after{display:none}
.landsteps li b{display:block;font-size:16.5px}
.landsteps li span{display:block;color:var(--soft);font-size:14px;line-height:1.55;margin-top:4px}
@media (max-width:900px){
  .landsteps{grid-template-columns:1fr;gap:14px}
  .landsteps li{padding:0 0 0 56px}
  .landsteps li::before{position:absolute;left:0;top:0;margin:0}
  .landsteps li::after{left:19px;top:40px;right:auto;bottom:-14px;width:2px;height:auto;
    background:linear-gradient(180deg,var(--line2),var(--line))}
}

/* ---------- программа курса: дорога из пяти миров ----------
   Слева вертикальный рельс с узлами — тот же приём, что у шагов урока, и по
   той же причине: пять миров проходят ПО ПОРЯДКУ, и порядок должен быть
   виден, а не подразумеваться. Рельс выдерживает любую ширину, в отличие от
   ломаной дороги по диагонали, которая на телефоне превращается в кашу. */
.landworlds{display:grid;gap:10px;position:relative;padding-left:0}
.landworld{position:relative;display:grid;grid-template-columns:46px minmax(0,1fr);
  gap:15px;align-items:start;border:1px solid var(--line);border-radius:18px;
  background:var(--panel);padding:14px 18px;overflow:hidden;transition:.18s}
.landworld:hover{border-color:var(--wc);transform:translateY(-2px);box-shadow:var(--sh)}
/* Цветная полоса слева — единственное, чем миры отличаются друг от друга
   на расстоянии вытянутой руки. */
.landworld::before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;background:var(--wc)}
/* Крупная цифра мира призраком в углу: она не для чтения, а для того, чтобы
   пятая карточка не выглядела такой же, как первая. */
.lwno{position:absolute;right:14px;top:-4px;font-family:'Fredoka','Inter',sans-serif;
  font-size:62px;line-height:1;color:var(--wc);opacity:.13;pointer-events:none}
.landworld .lwico{width:46px;height:46px;border-radius:15px;background:var(--wcbg);
  display:flex;align-items:center;justify-content:center;font-size:24px;flex:none}
.lwbody{min-width:0}
.lwkick{font-size:11.5px;letter-spacing:.06em;text-transform:uppercase;
  color:var(--wc);font-weight:700}
.lwbody b{font-size:18px}
.lwbody p{margin:3px 0 0;color:var(--soft);font-size:14.5px;line-height:1.5}
/* Названия уроков — фишками, а не строкой через точку. Строка читалась как
   один длинный текст, из которого не видно, что это перечень тем. */
.lwlist{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.lwlist span{font-size:12px;color:var(--soft);background:var(--sunken);
  border:1px solid var(--line);border-radius:8px;padding:4px 9px}
.lwlist span.more{color:var(--faint);background:none;border-style:dashed}
/* Имя босса переехало в строку-указатель над названием мира: отдельной
   строкой с рамкой оно добавляло каждой из пяти карточек полтора сантиметра
   высоты, а страница не должна быть длинной (правило фаундера 06.09.2026). */

/* ---------- карточки ---------- */
.landgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:14px}
/* Число колонок задаётся разделом, а не подбирается автоматически. Причина
   простая и видная глазом: auto-fit при шести карточках раскладывает их
   4 + 2, и раздел заканчивается дырой в пол-экрана. Колонка, на которую
   делится КОНКРЕТНЫЙ список, известна заранее — её и ставим. */
.landgrid.g2{grid-template-columns:repeat(2,minmax(0,1fr))}
.landgrid.g3{grid-template-columns:repeat(3,minmax(0,1fr))}
.landgrid.g4{grid-template-columns:repeat(4,minmax(0,1fr))}
@media (max-width:900px){
  .landgrid.g2,.landgrid.g3,.landgrid.g4{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:600px){
  .landgrid.g2,.landgrid.g3,.landgrid.g4{grid-template-columns:minmax(0,1fr)}
}
.landcard{border:1px solid var(--line);border-radius:var(--r);background:var(--panel);
  padding:20px;display:flex;flex-direction:column;gap:4px;transition:.18s}
.landcard:hover{border-color:var(--line2);transform:translateY(-2px);box-shadow:var(--sh)}
/* Значок на подложке, а не голой эмодзи. Голая эмодзи в потоке текста
   выглядит опечаткой; плитка делает из неё значок и заодно выравнивает
   карточки между собой — эмодзи у разных наборов разной высоты. */
.landcard .lcem{width:44px;height:44px;border-radius:14px;background:var(--panel2);
  border:1px solid var(--line);display:flex;align-items:center;justify-content:center;
  font-size:22px;margin-bottom:8px}
.landcard b{font-size:16.5px}
.landcard p{margin:0;color:var(--soft);font-size:14px;line-height:1.55}
/* Карточка направления шире обычной: у неё внутри абзац с числами, а не
   строка-подпись. На узкой сетке она бы резалась на четыре слова в строку. */
.landcard.wide{grid-column:span 2}
@media (max-width:760px){ .landcard.wide{grid-column:span 1} }
/* Направления — единственные карточки с цветом: они отвечают на «а это точно
   не курсы питона для малышей», и им разрешено быть заметнее остальных. */
.landcard.dir{background:linear-gradient(160deg,var(--panel),var(--panel2))}
.landcard.dir .lcem{background:var(--wcbg);border-color:transparent;color:var(--wc)}
.landcard.dir b{color:var(--wc)}

/* ---------- границы обещания ----------
   Раньше это были четыре жёлтых полосы подряд — экран аварийного щита. Читать
   их страшно, а написано там честное и полезное. Теперь это один документ:
   рамка одна, а строки внутри помечены знаком «этого здесь нет». */
.landhonest{border:1px solid var(--warnline);background:var(--warnbg);border-radius:20px;
  padding:8px 22px;list-style:none;margin:0}
.landhonest li{position:relative;padding:15px 0 15px 32px;font-size:14.5px;line-height:1.6;
  color:var(--warnink);border-bottom:1px solid var(--warnline)}
.landhonest li:last-child{border-bottom:none}
.landhonest li::before{content:"—";position:absolute;left:6px;top:15px;
  font-weight:700;color:var(--warn)}
.landhonest li b{color:var(--ink)}

/* ---------- устный ответ в кабинете взрослого ----------
   Карточка, по которой родитель спрашивает ребёнка вслух. Правильный ответ
   спрятан в <details> НЕ ради красоты: родитель читает вопрос с экрана, и
   если ответ лежит рядом открытым, он его проговаривает раньше ребёнка. */
.card.oral .oralcode{margin:12px 0;padding:12px 14px;border:1px solid var(--line);
  border-radius:12px;background:var(--code);color:var(--codeink);overflow-x:auto;
  font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.6}
.orall{margin:0;padding-left:22px;display:grid;gap:14px}
.orall li b{display:block;font-size:15px;line-height:1.45}
.orall li .dim{display:block;font-size:13px;line-height:1.5;margin-top:5px}
.orala{margin-top:7px}
.orala summary{display:inline-block;cursor:pointer;font-size:13px;font-weight:600;
  color:var(--accink);background:var(--sunken);border:1px solid var(--line);
  border-radius:9px;padding:5px 11px;list-style:none}
.orala summary::-webkit-details-marker{display:none}
.orala summary:hover{border-color:var(--acc)}
.orala[open] summary{color:var(--faint)}
.orala pre{margin:8px 0 0;padding:10px 12px;border-radius:10px;background:var(--okbg);
  border:1px solid var(--okline);color:var(--okink);
  font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.55;white-space:pre-wrap}

/* ---------- четыре больших блока ----------
   «Надо выделить важное большими блоками, чтобы бросалось в глаза» — указание
   фаундера 06.09.2026. Отличаются от обычных карточек тремя вещами разом:
   размером значка, размером заголовка и подложкой-градиентом. Иначе большой
   блок читается как просто ещё одна карточка, и весь смысл теряется.
   ⚠️ Их ровно четыре и больше быть не должно: пять «самых важных» вещей —
   это ноль важных вещей. */
.bigs{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}
.big{position:relative;overflow:hidden;border:1px solid var(--line);border-radius:20px;
  background:linear-gradient(160deg,var(--panel),var(--panel2));padding:24px 26px;
  box-shadow:var(--sh);transition:.18s}
.big:hover{transform:translateY(-2px);border-color:var(--line2)}
/* Значок крупный и приподнят над заголовком: он и есть то, что «бросается». */
.big .bigem{display:block;font-size:34px;line-height:1;margin-bottom:12px}
.big b{display:block;font-size:21px;line-height:1.2;letter-spacing:-.01em;margin-bottom:8px}
.big p{margin:0;color:var(--soft);font-size:14.5px;line-height:1.6}
.big p b{display:inline;font-size:inherit;margin:0;color:var(--ink)}
/* Строчка «почему это важно» отбита чертой: это вывод, а не продолжение
   описания, и читать её должны отдельно от него. */
.bigwhy{display:block;margin-top:14px;padding-top:12px;border-top:1px dashed var(--line);
  font-size:13px;line-height:1.5;color:var(--accink)}
@media (max-width:820px){ .bigs{grid-template-columns:1fr} }

/* ---------- вкладки внутри страницы ----------
   Главный инструмент против длины. Восемь карточек «Взрослому» и два раздела
   подряд («как проходит урок» + «не только язык») занимали три экрана;
   вкладками то же содержание занимает один, и каждый читает только своё.
   ⚠️ Это НЕ вкладки верхней панели (.tab): тех ровно три, за этим следит
   тест, и путать их нельзя ни классом, ни видом. */
.ltabs{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px}
.ltab{display:flex;align-items:center;gap:8px;border:1px solid var(--line);
  background:var(--panel);border-radius:13px;padding:9px 14px;font:inherit;
  font-size:14.5px;font-weight:600;color:var(--soft);cursor:pointer;transition:.16s;
  text-align:left}
.ltab:hover{border-color:var(--line2);color:var(--ink)}
.ltab.on{border-color:transparent;background:var(--acc);color:var(--onacc);
  box-shadow:0 10px 22px -12px var(--acc)}
.ltab .lte{font-size:17px;line-height:1}
/* Вкладки миров красятся в цвет своего мира — тот же приём, что на дороге
   курса: пять одинаковых кнопок не читаются как пять разных миров.
   ⚠️ Модификатор называется .wld, а не .world, и это не вкусовщина: `.world`
   в этом файле давно занят карточкой мира на карте курса (градиент, рамка,
   отступы), и вкладки молча получали её фон — белую плашку вокруг всего
   ряда. Любой новый класс вывески сначала проверяется на столкновение с
   тем, что уже есть в style.css. */
.ltabs.wld .ltab.on{background:var(--wc);box-shadow:0 10px 22px -12px var(--wc)}
.ltabs.wld .ltab .ltt{display:flex;flex-direction:column;line-height:1.25}
.ltabs.wld .ltab .ltt i{font-style:normal;font-size:11px;letter-spacing:.05em;
  text-transform:uppercase;opacity:.72}
.ltabs.wld .ltab .ltt b{font-size:14.5px;font-weight:700}
/* Мелкий ряд — это ПЕРЕКЛЮЧАТЕЛЬ ВНУТРИ вкладки, а не вторые вкладки рядом.
   Жалоба фаундера: два одинаковых ряда пилюль подряд читаются как один
   перенесённый ряд, и непонятно, что чему подчинено. Поэтому здесь другой
   вид: подпись слева, кнопки в одной обойме, без тени и без заливки
   акцентом — выбранная просто светлее фона обоймы. */
.ltabs.ltsm{display:inline-flex;flex-wrap:wrap;align-items:center;gap:4px;
  background:var(--sunken);border:1px solid var(--line);border-radius:12px;
  padding:4px 4px 4px 11px;margin-bottom:14px}
.ltabs.ltsm .ltlbl{font-size:12px;color:var(--faint);margin-right:4px;white-space:nowrap}
.ltabs.ltsm .ltab{padding:5px 11px;font-size:13px;border-radius:9px;border-color:transparent;
  background:transparent;box-shadow:none;color:var(--soft)}
.ltabs.ltsm .ltab:hover{background:var(--panel2);border-color:transparent;color:var(--ink)}
.ltabs.ltsm .ltab.on{background:var(--panel);border-color:var(--line2);color:var(--accink);
  box-shadow:0 1px 2px rgba(28,35,80,.08)}
.ltabs.ltsm .ltab .lte{font-size:15px}
.ldpane{min-height:60px}
.ldpanefoot{margin:12px 0 0;font-size:13px;color:var(--faint)}

/* Приписка к шагам урока: то, что живёт внутри урока, но шагом не является.
   Отбита рамкой, чтобы не читалась пятым шагом. */
.instep{border:1px solid var(--line);border-radius:16px;background:var(--panel);
  padding:16px 18px;margin-top:16px}
.instepl{font-size:11.5px;letter-spacing:.06em;text-transform:uppercase;
  color:var(--acc2);font-weight:700;margin-bottom:10px}

/* ---------- живые блоки: черепашка и разминка ----------
   Пожелание фаундера 06.09.2026: «чтобы люди игрались, нажимали, и что-то
   оживало». Обе штуки работают настоящим движком, как и окно в шапке, —
   скриншотов и записанных гифок здесь нет и не будет. */
.drawwin{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);gap:16px;
  align-items:start}
.drawc{width:100%;display:block;border:1px solid var(--line);border-radius:16px;
  background:var(--board)}
.drawside{display:flex;flex-direction:column;gap:10px;min-width:0}
.drawside .dwcode{border:1px solid var(--line);border-radius:14px;background:var(--code);
  overflow:hidden}
.drawside .dwbtn{align-self:flex-start}
.livenote{margin:0;font-size:12.5px;color:var(--faint);line-height:1.5}
.warmask{display:grid;grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr);gap:18px;
  align-items:start}
.warmask .dwcode{border:1px solid var(--line);border-radius:14px;background:var(--code);
  overflow:hidden}
/* Обе колонки устроены одинаково: подпись, под ней коробка. Иначе рамка кода
   встаёт вровень с ТЕКСТОМ правой подписи и оказывается выше поля ответа. */
.warmcode{display:flex;flex-direction:column;gap:8px;min-width:0}
.warmans{display:flex;flex-direction:column;gap:8px;min-width:0}
.warmlbl,.warmans label{font-size:14px;font-weight:600}
.warmans textarea{width:100%;box-sizing:border-box;border:1px solid var(--line2);
  border-radius:12px;background:var(--panel);color:var(--ink);padding:10px 12px;
  font-family:'JetBrains Mono',monospace;font-size:13.5px;line-height:1.6;resize:vertical}
.warmans textarea:focus{outline:none;border-color:var(--acc)}
.warmans .dwbar{background:none;border:none;padding:0}
.warmres{display:none;border-radius:12px;padding:11px 13px;font-size:13.5px;line-height:1.55}
.warmres.show{display:block}
.warmres b{display:block;margin-bottom:3px}
.warmres.ok{background:var(--okbg);border:1px solid var(--okline);color:var(--okink)}
.warmres.ok b{color:var(--ok)}
.warmres.bad{background:var(--badbg);border:1px solid var(--badline);color:var(--badink)}
.warmres.bad b{color:var(--bad)}
.warmres.warn{background:var(--warnbg);border:1px solid var(--warnline);color:var(--warnink)}
/* Расхождение двумя колонками — ровно так его показывает урок: не «неверно»,
   а «вот твоё, вот нужное», рядом и построчно. */
.warmdiff{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:8px 0}
.warmdiff i{display:block;font-style:normal;font-size:11px;letter-spacing:.05em;
  text-transform:uppercase;opacity:.75;margin-bottom:3px}
.warmdiff pre{margin:0;padding:8px 10px;border-radius:9px;background:var(--sunken);
  color:var(--ink);font-family:'JetBrains Mono',monospace;font-size:12.5px;
  line-height:1.5;overflow-x:auto}
.warmwhy{display:block;color:var(--soft);font-size:13px;line-height:1.55}

/* ---------- витрина проектов ---------- */
.showwin{border:1px solid var(--line);border-radius:18px;background:var(--panel);
  overflow:hidden}
.shhead{display:flex;gap:14px;align-items:center;padding:13px 18px;
  border-bottom:1px solid var(--line);background:var(--panel2)}
.shico{width:44px;height:44px;border-radius:14px;background:var(--wcbg);flex:none;
  display:flex;align-items:center;justify-content:center;font-size:22px}
.shttl{min-width:0}
.shkick{font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--wc);
  font-weight:700}
.shttl b{font-size:17px}
.shttl p{margin:1px 0 0;color:var(--soft);font-size:13.5px;line-height:1.45}
/* Вывод ограничен по высоте и прокручивается внутри: «Свой сайт» печатает
   шестьдесят строк, и без потолка одна вкладка растянула бы страницу на
   пол-экрана — то, чего быть не должно. */
/* Результат и код рядом: вывод узкий, и на всю ширину страницы он выглядел
   пустой коробкой (жалоба фаундера). Обе колонки одной высоты и прокручиваются
   каждая в себе — «Свой сайт» печатает шестьдесят строк. */
.shbody{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  border-top:1px solid var(--line)}
.shcol{min-width:0;display:flex;flex-direction:column}
.shcol + .shcol{border-left:1px solid var(--line)}
.shlbl{padding:9px 16px;font-size:11px;letter-spacing:.05em;text-transform:uppercase;
  color:var(--faint);background:var(--panel2);border-bottom:1px solid var(--line)}
.ldout{margin:0;padding:14px 16px;height:270px;overflow:auto;
  font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.55;
  color:var(--outink);white-space:pre;background:var(--res)}
.ldcode{background:var(--code);height:270px;overflow:auto}
.ldcode .dwcode{border:none}
/* Витрина показывает чужую готовую программу, а не редактор: читать её надо
   глазами и целиком. Поэтому длинные строки переносятся, а не уезжают вправо
   под полосу прокрутки, которую в macOS ещё и не видно. */
.ldcode.flow pre{white-space:pre-wrap;overflow-wrap:anywhere;overflow-x:visible}
@media (max-width:760px){
  .shbody{grid-template-columns:1fr}
  .shcol + .shcol{border-left:none;border-top:1px solid var(--line)}
  .ldout,.ldcode{height:200px}
}

/* ---------- взрослому: три роли ---------- */
.rolepane{border:1px solid var(--line);border-radius:18px;background:var(--panel);
  padding:18px 20px}
.rolein{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.8fr);gap:22px;
  align-items:start}
.rolein.one{grid-template-columns:minmax(0,1fr)}
.rolehow{display:inline-block;font-size:12px;color:var(--acc2);font-weight:600;
  background:var(--panel2);border:1px solid var(--line);border-radius:999px;
  padding:5px 11px;margin-bottom:10px}
.rolelede{margin:0 0 14px;color:var(--soft);font-size:14.5px;line-height:1.55}
/* Строки, а не карточки: восемь карточек фаундер прочитать не смог, и он
   прав — карточка обещает отдельную мысль, а здесь их пять от одного лица. */
.rolelist{list-style:none;margin:0;padding:0;display:grid;gap:9px}
.rolelist li{display:flex;gap:11px;align-items:flex-start;font-size:14px;line-height:1.55;
  color:var(--soft)}
.rolelist .rlem{flex:none;width:26px;text-align:center;font-size:17px;line-height:1.4}
.rolelist b{color:var(--ink)}
.roledemo{border:1px solid var(--line);border-radius:15px;background:var(--panel2);
  padding:14px 16px}
.rdhead{font-size:12.5px;color:var(--faint);line-height:1.5;margin-bottom:10px}
.hwtop{display:flex;gap:10px;align-items:center;margin-bottom:8px}
.hwem{font-size:22px;line-height:1}
.hwtop b{display:block;font-size:15px}
.hwtop i{font-style:normal;font-size:12px;color:var(--faint)}
.hwtop .dwbtn{margin-left:auto;flex:none}
.hwgoal{margin:0 0 10px;font-size:13.5px;line-height:1.55;color:var(--soft)}
.hwans{border-top:1px dashed var(--line);padding-top:9px}
.hwans i{display:block;font-style:normal;font-size:11px;letter-spacing:.05em;
  text-transform:uppercase;color:var(--faint);margin-bottom:4px}
.hwans pre{margin:0;font-family:'JetBrains Mono',monospace;font-size:13px;
  line-height:1.5;color:var(--ink);white-space:pre-wrap}
@media (max-width:900px){
  .drawwin,.warmask,.rolein{grid-template-columns:1fr}
}

/* ---------- приборная панель: один вид в двух местах ----------
   На вывеске это НЕРАБОЧИЙ макет («вот как выглядит ваш кабинет»), в самом
   кабинете — те же плитки, но кнопки. Классы общие нарочно: посетитель,
   дошедший до кабинета, обязан узнать то, что видел на витрине.
   ⚠️ Макет на вывеске не показывает НИКАКИХ чисел. Выдуманный отчёт про
   несуществующего ребёнка — ровно то враньё, от которого продукт
   отказывается внутри (в панели репетитора имён детей нет).
   ⚠️ Плитка не ниже 76 px: это цель для пальца (docs/pravila-sajta.md § 8). */
.lkmock{border:1px solid var(--line);border-radius:16px;background:var(--panel2);overflow:hidden}
.lkbar{display:flex;align-items:center;gap:9px;padding:9px 13px;background:var(--sunken);
  border-bottom:1px solid var(--line);font-size:12.5px;color:var(--faint);flex-wrap:wrap}
.lkdots{display:flex;gap:4px;flex:none}
.lkdots i{width:8px;height:8px;border-radius:99px;background:var(--line2);display:block}
.lkbar b{font-size:12.5px;color:var(--soft);font-weight:600}
.lkbar .tag{margin-left:auto}
.lkgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px;padding:13px}
.lkgrid.live{padding:0;background:none;margin:0 0 18px}
/* В макете плитки шире: семь штук по пять в ряд давали 5+2 и дыру в
   полстроки — панель так не выглядит. По четыре в ряд ряды ровнее. */
.lkmock .lkgrid{grid-template-columns:repeat(auto-fill,minmax(220px,1fr))}
.lktile{display:flex;flex-direction:column;gap:2px;text-align:left;min-height:76px;
  border:1px solid var(--line);border-radius:13px;background:var(--panel);
  padding:11px 13px;color:inherit;font-family:inherit}
.lktile .lke{font-size:19px;line-height:1.1}
.lktile b{font-size:14.5px;line-height:1.25}
.lktile span{font-size:12.5px;color:var(--faint);line-height:1.4}
.lktile .lkval{font-family:'Fredoka','Inter',sans-serif;font-size:27px;line-height:1.05;
  color:var(--acc2);margin-top:auto}
button.lktile{cursor:pointer;transition:.15s}
button.lktile:hover{border-color:var(--acc);background:var(--panel2);transform:translateY(-2px)}
button.lktile.go{border-color:var(--acc);box-shadow:inset 0 0 0 1px var(--acc)}
@media (max-width:520px){
  /* ⚠️ Макет тоже: у «.lkmock .lkgrid» вес больше, чем у «.lkgrid», а
     медиазапрос веса не добавляет — без второго имени плитки на телефоне
     встают по одной в ряд, и семь штук растягивают раздел на полтора экрана. */
  .lkgrid,.lkmock .lkgrid{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;padding:10px}
  .lktile{min-height:70px;padding:10px}
  .lktile b{font-size:13.5px}
}

/* ---------- одна навигация на все экраны кабинета ----------
   Экранов у репетитора три — ученики, группа, панель, — и попасть в «Группу»
   можно было только набрав адрес с #group: ссылки на неё не было ни на одном
   экране. Полоса стоит на всех трёх и всегда показывает, где ты сейчас. */
.roomnav{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 18px}
.roomnav button{border:1px solid var(--line2);background:var(--panel);color:var(--soft);
  border-radius:11px;padding:9px 14px;font-size:13.5px;font-weight:600;cursor:pointer;transition:.15s}
.roomnav button:hover{color:var(--ink);border-color:var(--acc)}
.roomnav button.on{background:var(--acc);color:var(--onacc);border-color:transparent}

/* ---------- сводка кабинета взрослого ----------
   Четыре числа над вкладками и строка «Сейчас важно» о затыке. Приёмы из
   замера конкурентов 12.09.2026 — docs/kabinet-benchmark-2026-09-12.md. */
.cabsum{margin-bottom:6px}
.cabnow{background:var(--warnbg);border:1px solid var(--warnline);color:var(--warnink);
  border-radius:12px;padding:10px 14px;margin:0 0 12px;font-size:14.5px}

/* ---------- карта экзамена: все задания по номерам ----------
   Строка на задание, а не карточка: заданий 27, и карточками это была бы
   стена, по которой не пробежать глазами. Читателю тут нужно одно движение —
   сверху вниз, «что есть, чего нет».
   ⚠️ Три состояния различаются ЦВЕТОМ ЛЕВОГО КРАЯ и словом, а не только
   цветом: дальтонизм и чёрно-белая печать не должны стирать разницу. */
.extabs{margin-bottom:14px}
.extally{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 14px;font-size:13px}
.extally span{border:1px solid var(--line);border-radius:11px;padding:6px 11px;background:var(--panel2)}
.extally .exok{color:var(--ok)}
.extally .exno{color:var(--faint)}
.extally .expart{color:var(--warn)}

/* ---------- поле Робота ----------
   Клетки — сетка из <i>, а не картинка: поле читается программой чтения с
   экрана, масштабируется без мыла и не требует ни одного байта картинок.
   ⚠️ Робот и закрашенная клетка различаются НЕ только цветом: у робота стоит
   значок. Одного цвета мало — дальтонизм и чёрно-белая печать его стирают. */
.rbf{display:grid;grid-template-columns:repeat(var(--rbw),minmax(0,1fr));gap:2px;
  max-width:340px;margin:0 0 10px;background:var(--line);border:1px solid var(--line2);
  border-radius:10px;padding:2px}
.rbc{aspect-ratio:1;display:flex;align-items:center;justify-content:center;
  background:var(--panel);border-radius:3px;font-size:15px;font-style:normal;line-height:1}
.rbc.wall{background:var(--ink)}
.rbc.paint{background:var(--acc-lt)}
.rbwrap{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.2fr);gap:18px;margin:0 0 16px}
.rbhead{font-size:12.5px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
  color:var(--faint);margin:0 0 8px}
.rbcode{width:100%;box-sizing:border-box;background:var(--code);border:1px solid var(--line2);
  border-radius:12px;padding:12px 14px;color:var(--ink);font-size:15px;line-height:1.6;
  font-family:'JetBrains Mono','SF Mono',Menlo,monospace;resize:vertical}
.rbcode:focus{outline:none;border-color:var(--acc)}
.rbpair{display:flex;flex-wrap:wrap;gap:18px;margin:10px 0 0}
.rbpair .rbf{max-width:190px}
.rbref{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px}
.rbref b{display:block;font-size:12.5px;color:var(--faint);margin:0 0 4px}
.rbref code{display:block;background:var(--sunken);border-radius:8px;padding:6px 9px;
  margin:0 0 5px;font-size:13px;line-height:1.5;color:var(--codeink)}
.rbhints{margin:0;padding-left:20px;font-size:14px;line-height:1.6;color:var(--soft)}
.rbhints li{margin:0 0 6px}
@media (max-width:720px){
  .rbwrap{grid-template-columns:minmax(0,1fr)}
  .rbf{max-width:280px}
}
.exrow.part{border-left-color:var(--warn)}
.exrow.part .exn{color:var(--warn)}
.exmap{display:flex;flex-direction:column;gap:6px;margin:0 0 18px}
.exrow{display:grid;grid-template-columns:38px minmax(0,1fr) auto;align-items:center;gap:12px;
  border:1px solid var(--line);border-left:3px solid var(--line2);border-radius:12px;
  padding:10px 14px;background:var(--panel)}
.exrow.yes{border-left-color:var(--ok)}
.exrow.soon{border-left-color:var(--acc)}
.exrow.no{border-left-color:var(--line2);background:var(--panel2)}
.exn{font-weight:700;font-size:15px;color:var(--faint);text-align:right}
.exrow.yes .exn{color:var(--ok)}
.ext{font-size:14px;color:var(--ink);line-height:1.4}
.exrow.no .ext{color:var(--soft)}
.exact{display:flex;align-items:center;gap:10px;white-space:nowrap}
.excnt{font-size:12.5px;color:var(--faint)}
.exwhy{font-size:12.5px;color:var(--faint)}
@media (max-width:620px){
  .exrow{grid-template-columns:30px minmax(0,1fr);row-gap:8px;padding:10px 12px}
  .exact{grid-column:2;justify-content:flex-start}
  .exwhy,.excnt{font-size:12px}
}

.roomhint{margin:-6px 0 14px;font-size:13px;line-height:1.55;color:var(--faint)}
.roomhint b{color:var(--soft);font-weight:600}

/* ---------- ЕГЭ и ОГЭ на вывеске ----------
   Два числа рядом и список под ними. Сетка на две колонки и одинаковые
   карточки — раздел обязан читаться за секунду, а не разбираться. */
.exlanding{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:14px;margin:0 0 16px}
.exlbig{border:1px solid var(--line);border-radius:16px;padding:18px 20px;background:var(--panel);
  display:flex;flex-direction:column;gap:4px}
.exlnum{font-family:'Fredoka',system-ui,sans-serif;font-size:34px;line-height:1.1;color:var(--acc)}
.exlbig b{font-size:15px}
.exllist{list-style:none;margin:0 0 18px;padding:0;display:grid;gap:10px}
.exllist li{border-left:3px solid var(--line2);padding:2px 0 2px 14px;font-size:14.5px;line-height:1.5;color:var(--soft)}
.exllist li b{color:var(--ink)}
@media (max-width:620px){ .exlnum{font-size:28px} .exllist li{font-size:14px} }

/* ---------- пробный вариант ----------
   Строка варианта — та же строка карты экзамена (.exrow), только под темой
   задания стоит вторая строчка: наша задача на этот номер. Отдельной сетки
   она не заводит нарочно — карта и вариант обязаны читаться как одно место,
   иначе номер 24 в двух списках выглядит как два разных задания. */
.vartask{display:block;margin-top:3px;font-size:12.5px;color:var(--faint)}
.vartask b{color:var(--warn);font-weight:600}
.vexams{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px;margin:0 0 18px}
.vexams .card{margin:0}
@media (max-width:620px){ .vartask{font-size:12px} }

/* ---------- проверка «что умеет сам» ----------
   Строки итога — те же .exrow, что у карты экзамена: один язык «зелёное —
   сделано, жёлтое — с оговоркой». Своё здесь только три вещи: код результата
   крупно (его диктуют голосом), лесенка ступеней над задачей и поле кода. */
.prvcode{font-family:'JetBrains Mono',ui-monospace,monospace;font-size:26px;font-weight:600;
  letter-spacing:2px;color:var(--ink);background:var(--sunken);border:1px solid var(--line);
  border-radius:12px;padding:12px 16px;margin:4px 0 10px;overflow-wrap:anywhere}
.prvinline{font-family:'JetBrains Mono',ui-monospace,monospace;letter-spacing:1px}
.prvinput{font-family:'JetBrains Mono',ui-monospace,monospace;font-size:16px;letter-spacing:1px;
  text-transform:uppercase;padding:10px 12px;border:1px solid var(--line2);border-radius:10px;
  background:var(--panel);color:var(--ink);min-width:0;flex:1 1 220px}
.prvladder{display:grid;grid-template-columns:repeat(10,minmax(0,1fr));gap:6px;margin:0 0 14px}
.prvladder span{text-align:center;font-size:13px;font-weight:600;padding:6px 0;border-radius:8px;
  border:1px solid var(--line);background:var(--panel2);color:var(--faint)}
.prvladder .now{border-color:var(--acc);color:var(--acc);background:var(--panel)}
.prvladder .ok{border-color:var(--ok);color:var(--ok)}
.prvladder .miss{border-color:var(--line2);color:var(--soft);text-decoration:line-through}
.exrow.prv-yes{border-left-color:var(--ok)}
.exrow.prv-yes .exn{color:var(--ok)}
.exrow.prv-part{border-left-color:var(--warn)}
.exrow.prv-part .exn{color:var(--warn)}
.exrow.prv-miss{border-left-color:var(--bad)}
.exmap .exrow[class*="prv-"] .exact{white-space:normal;text-align:right}
.exrow.prv-no{border-left-color:var(--line2);background:var(--panel2)}
.exrow.prv-no .ext{color:var(--soft)}
.exrow .excnt b{font-weight:600;color:var(--ink)}
@media (max-width:620px){ .prvcode{font-size:20px;letter-spacing:1px} .prvladder{gap:3px} }

/* ---------- вход ----------
   Последний экран повторяет первый по фону: страница закрывается тем же
   жестом, каким открылась, и кнопка входа стоит на самом заметном месте
   страницы, а не на белом фоне между двумя разделами. */
/* Границы обещания и вход стоят В ОДНОМ блоке и рядом, а не двумя разделами
   подряд: раньше страница заканчивалась дважды и была на экран длиннее.
   Порядок внутри блока сохранён — границы слева, вход справа: обещание и его
   край читаются вместе, а не «сначала продали, потом оговорились». */
.landend{position:relative;overflow:hidden;border:1px solid var(--line);
  border-radius:26px;background:var(--panel);padding:32px 34px;box-shadow:var(--shbig)}
.landend > *:not(.lhaur){position:relative}
.endin{position:relative;display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);
  gap:30px;align-items:start}
.landend h2{margin:0 0 14px;font-size:26px;line-height:1.15;letter-spacing:-.015em}
.landend .lede{margin:0 0 18px;font-size:15.5px}
.landend .landsub{margin:16px 0 0}
.endright{border-left:1px solid var(--line);padding-left:30px}
@media (max-width:860px){
  .endin{grid-template-columns:1fr;gap:24px}
  .endright{border-left:none;border-top:1px solid var(--line);padding-left:0;padding-top:24px}
}

@media (max-width:980px){
  .lhin{grid-template-columns:1fr;gap:28px}
  .landhero h1{font-size:42px}
  .landnums{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:620px){
  .land{gap:40px}
  .landhero{padding:28px 20px 26px;border-radius:20px}
  .landhero h1{font-size:32px}
  .landlede{font-size:16px}
  .landsect h2{font-size:24px}
  .landend h2{font-size:26px}
  .landend{padding:28px 20px}
  .landcta .bigbtn{width:100%}
  .ldauthrow .bigbtn{width:100%}
  .ldauth{margin-top:20px}
  .landworld{grid-template-columns:44px minmax(0,1fr);gap:13px;padding:16px 16px 16px 18px}
  .landworld .lwico{width:44px;height:44px;border-radius:14px;font-size:22px}
  .lwno{font-size:56px;right:10px}
  .landnum{padding:14px 16px}
  .landnum b{font-size:28px}
  .dwhead .dwtag{display:none}
}
/* Подвал детской главной: дверь на вывеску для взрослого, взявшего планшет.
   Нарочно тихая — кнопка, а не карточка: ребёнку она не адресована. */
.landfoot{margin-top:28px;padding-top:18px;border-top:1px solid var(--line);text-align:center}
/* Строка ссылок на сайт: мельче и тише, чем «О тренажёре» над ней. Ребёнку
   она не мешает — он до подвала не долистает; взрослый ищет именно тут. */
.footlinks{margin-top:10px;font-size:12.5px;color:var(--faint);line-height:1.9}
.footlinks span{color:var(--faint)}
.footlinks a{color:var(--faint);text-decoration:none;border-bottom:1px solid var(--line)}
.footlinks a:hover{color:var(--accink);border-bottom-color:var(--accink)}
.linkbtn{background:none;border:none;padding:6px 10px;cursor:pointer;font:inherit;
  font-size:13.5px;color:var(--faint);border-radius:9px}
.linkbtn:hover{color:var(--accink);background:var(--sunken)}
/* ===== вход в свой кабинет: вкладка в шапке =====
   Выглядит как вкладка, но живёт снаружи .tabs — иначе её прятало бы
   правило .adminui .tabs, а нужна она именно там. Место — справа, рядом
   с «?»: на любом сайте вход ищут в правом верхнем углу, и спорить с этой
   привычкой дороже, чем ей подчиниться. */
.lktab{border:1px solid var(--line2);background:var(--panel);color:var(--ink);
  border-radius:11px;padding:7px 13px;font-size:13.5px;font-weight:600;
  cursor:pointer;transition:.15s;white-space:nowrap;display:flex;align-items:center;gap:6px}
.lktab:hover{border-color:var(--acc);background:var(--panel2)}
.lktab[hidden]{display:none}
/* Гостю вход — главное действие на экране, поэтому он не серый, а акцентный:
   у гостя в шапке всего две кнопки, и одна из них не должна теряться. */
.lktab.go{background:var(--acc);border-color:transparent;color:var(--onacc)}
.lktab.go:hover{background:var(--acc-lt);border-color:transparent}
@media (max-width:640px){ .lktab .lbl{display:none} .lktab{padding:7px 10px} }

/* ---------- карусель карточек на телефоне ----------
   ⚠️ Здесь ТОЛЬКО косметика. Всю раскладку — display, ширину карточки,
   прилипание — ставит скрипт свойствами элементов (landSwipeInit в js/app.js),
   и причина записана там же. Правило отсюда не может ни сломать ряд, ни
   растянуть страницу: оно прячет полосу прокрутки и рисует точки.

   Полоса прокрутки спрятана намеренно: с ней ряд выглядит как ошибка вёрстки,
   а не как то, что надо листать. Вместо неё — выглядывающий край следующей
   карточки и точки под рядом. */
.swipe{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch}
.swipe::-webkit-scrollbar{display:none}
.swdots{display:flex;justify-content:center;gap:7px;margin:10px 0 0}
/* ⚠️ Обязательно: display:flex выше перебивает встроенное поведение hidden,
   и без этого правила точки видны на широком экране, где карусели нет. */
.swdots[hidden]{display:none}
.swdots i{width:7px;height:7px;border-radius:50%;background:var(--line2);
  transition:.2s;cursor:pointer}
.swdots i.on{background:var(--acc);transform:scale(1.35)}

/* ---------- переключатели на телефоне: по два в ряд ----------
   Просьба фаундера 07.09.2026: «переключатели идут вниз, а можно два в
   горизонталь, потом ниже по порядку, если ширина экрана позволяет».

   Было `flex-wrap:wrap`, и переносило честно — только подписи длинные
   («Репетитору и учителю», «Мир 4 · Настоящий Python»), в строку помещалась
   ровно одна кнопка, и пять вкладок миров занимали 232 пикселя, то есть треть
   экрана телефона ДО того, как начнётся содержимое.

   Сетка в две колонки решает это без единой правки разметки: подпись внутри
   кнопки переносится сама, а высота ряда падает вдвое.

   ⚠️ `.ltsm` исключены. Это мелкие вкладки с подписью слева («Что рисуем:»,
   «Разминка:»), они живут одной строкой вместе с этой подписью, и сетка
   выбросила бы подпись в отдельную ячейку.
   ⚠️ Правило стоит в конце файла: у `.ltabs` есть свой `display:flex` выше, и
   при равной силе решает порядок. */
@media (max-width:640px){
  .ltabs:not(.ltsm){display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
    align-items:stretch}
  .ltabs:not(.ltsm) .ltab{justify-content:flex-start;padding:9px 11px}
}
