/* ============================================================
   Тема в духе старого форумного интернета: фиолетовая идентичность
   на почти чёрном, блоки с отдельными шапками, плотные строки,
   неоновое свечение на акцентах.
   ============================================================ */
:root{
  --bg:#101012; --bg2:#17171b; --bg3:#1f1f26; --bg4:#26262f;
  --deep:#0a0223; --indigo:#322c75;
  --line:#2a2a33; --line2:#3a3a47;
  --fg:#ffffff; --fg2:#c9bcf8; --fg3:#8c8c8c;
  --vio:#9379f0; --vio2:#9c91ff; --blue:#6293fd; --hot:#ff512f; --ok:#7ee787;
  --s1:#8c8c8c; --s2:#9379f0; --s3:#ff512f;
  --rd:0px; --w:min(760px,100%);
  --mono:"Consolas","DejaVu Sans Mono","Courier New",monospace;
}
*{box-sizing:border-box}
html,body{margin:0;height:100%;overflow:hidden}
body{
  background:#07070a;
  color:var(--fg);
  font:15px/1.62 "Segoe UI","Helvetica Neue",Helvetica,Roboto,Arial,sans-serif;
  -webkit-font-smoothing:antialiased;
  display:grid;place-items:center;
}

/* фоновое видео на весь экран, размытое — окно приложения лежит поверх */
#bgvid{
  position:fixed;inset:0;width:100%;height:100%;object-fit:cover;z-index:-2;
  filter:blur(13px) saturate(1.15) brightness(.5);transform:scale(1.09);
  pointer-events:none;
}
#bgtint{
  position:fixed;inset:0;z-index:-1;pointer-events:none;
  background:
    radial-gradient(1000px 620px at 20% 8%, rgba(147,121,240,.2), transparent 62%),
    radial-gradient(900px 520px at 84% 12%, rgba(98,147,253,.14), transparent 60%),
    linear-gradient(180deg, rgba(10,2,35,.72), rgba(7,7,10,.88));
}

#boot{padding:40px;color:var(--fg3);font-family:var(--mono)}

/* окно 4:3 по центру — как монитор той эпохи */
#shell{
  display:grid;grid-template-columns:296px 1fr;
  width:min(100vw, calc(100vh * 4 / 3));
  height:min(100vh, calc(100vw * 3 / 4));
  background:var(--bg);
  border:1px solid var(--line2);
  box-shadow:0 0 0 1px rgba(0,0,0,.6), 0 22px 70px rgba(0,0,0,.75), 0 0 90px rgba(147,121,240,.14);
  overflow:hidden;
}
#shell.has-panel{grid-template-columns:266px 1fr 330px}
/* Шапка с гамбургером и затемнение нужны только там, где боковая уезжает
   за край экрана. На широком окне их нет вовсе — иначе они встали бы
   лишними ячейками сетки #shell. */
#topbar,#scrim{display:none}

/* ---------------- боковая ---------------- */
#side{background:var(--bg2);border-right:1px solid var(--line);display:flex;flex-direction:column;overflow:hidden}
.brand{
  padding:14px 15px 12px;border-bottom:1px solid var(--line);
  background:linear-gradient(180deg,rgba(147,121,240,.16),transparent);
}
.brand-t{
  font-weight:700;letter-spacing:.4px;color:var(--vio2);
  text-shadow:0 0 14px rgba(147,121,240,.55);
}
.brand-t::after{content:" ( ´ ω ` )";color:var(--fg3);font-weight:400;font-size:11px;text-shadow:none}
.brand-s{font:11px/1.5 var(--mono);color:var(--fg3);margin-top:4px}

.nav{display:flex;flex-wrap:wrap;gap:3px;padding:9px 11px;border-bottom:1px solid var(--line)}
/* Кнопки растягиваются на всю ширину строки. Иначе последний ряд обрывается
   раньше остальных, и блок выглядит съехавшим влево. */
.navbtn{
  flex:1 1 auto;min-width:0;white-space:nowrap;
  background:var(--bg3);border:1px solid var(--line);color:var(--fg3);
  padding:4px 9px;border-radius:3px;cursor:pointer;font:12px/1 var(--mono);
  transition:all .15s;
}
.navbtn:hover{border-color:var(--vio);color:var(--fg2)}
.navbtn.is-on{background:var(--indigo);border-color:var(--vio);color:#fff;box-shadow:0 0 10px rgba(147,121,240,.35)}

.filters{padding:10px 11px;border-bottom:1px solid var(--line);display:flex;flex-direction:column;gap:7px}
.fl-h{font:10px/1 var(--mono);text-transform:uppercase;letter-spacing:1.2px;color:var(--vio);opacity:.85}
.fl-row{display:flex;gap:3px}
.chip{
  background:var(--bg3);border:1px solid var(--line);color:var(--fg3);
  border-radius:3px;padding:3px 8px;cursor:pointer;font:11px/1.3 var(--mono);transition:all .15s;
}
.chip:hover{border-color:var(--line2);color:var(--fg2)}
.chip.is-on{border-color:var(--vio);color:#fff;background:rgba(147,121,240,.18);box-shadow:0 0 8px rgba(147,121,240,.3)}
.filters select,.filters input[type=search]{
  background:var(--bg3);border:1px solid var(--line);color:var(--fg);
  border-radius:3px;padding:5px 7px;font-size:12.5px;width:100%;font-family:inherit;
}
.filters select:focus,.filters input:focus{outline:none;border-color:var(--vio);box-shadow:0 0 0 2px rgba(147,121,240,.18)}
.ck{font-size:12px;color:var(--fg3);display:flex;gap:6px;align-items:center;cursor:pointer}
.ck:hover{color:var(--fg2)}

.sidelist{flex:1;overflow:auto;padding:6px 7px 16px}
.tgroup{margin:0 0 3px}
.thead{
  display:flex;justify-content:space-between;align-items:baseline;gap:6px;
  padding:5px 8px;border-radius:3px;cursor:pointer;border:1px solid transparent;transition:all .15s;
}
.thead:hover{background:var(--bg3);border-color:var(--line)}
.thead.is-on{background:linear-gradient(90deg,rgba(147,121,240,.2),rgba(147,121,240,.04));border-color:var(--line2)}
.tname{font-size:13px;font-weight:600;color:var(--fg)}
.thead.is-on .tname{color:var(--vio2)}
.tmeta{font:10.5px var(--mono);color:var(--fg3);white-space:nowrap}
.titem{
  display:flex;gap:7px;align-items:flex-start;
  padding:4px 8px 4px 13px;border-radius:3px;cursor:pointer;font-size:12.5px;color:var(--fg3);
  border-left:2px solid transparent;
}
.titem:hover{background:var(--bg3);color:var(--fg2);border-left-color:var(--line2)}
.titem.is-on{background:rgba(50,44,117,.5);color:#fff;border-left-color:var(--vio)}
.titem.done .tt{opacity:.45;text-decoration:line-through}
.tstar{font-size:9px;letter-spacing:-1px;flex:none;padding-top:3px;font-family:var(--mono)}
.s1{color:var(--s1)} .s2{color:var(--s2)} .s3{color:var(--s3)}
.tt{flex:1;min-width:0}

.progress-box{padding:9px 13px;border-top:1px solid var(--line);font:11px var(--mono);color:var(--fg3);background:var(--bg2)}
.pb-row{display:flex;justify-content:space-between;margin-bottom:5px}
.pb-row b{color:var(--vio2)}
.bar{height:6px;background:var(--bg);border:1px solid var(--line);border-radius:2px;overflow:hidden}
.bar i{display:block;height:100%;width:0;transition:width .35s ease;
  background:linear-gradient(90deg,var(--indigo),var(--vio));box-shadow:0 0 8px rgba(147,121,240,.6)}
.tiny{
  margin-top:8px;background:var(--bg3);border:1px solid var(--line);color:var(--fg3);
  font:10px var(--mono);padding:3px 7px;border-radius:3px;cursor:pointer;
}
.tiny:hover{border-color:var(--hot);color:var(--hot)}

/* ---------------- основная ---------------- */
#main{overflow:auto;padding:22px 30px 90px}
.wrap{max-width:var(--w);margin:0 auto}
h1{
  font-size:22px;margin:0 0 16px;font-weight:700;letter-spacing:.2px;
  color:#fff;text-shadow:0 0 18px rgba(147,121,240,.4);
}
h2{
  font-size:16px;margin:26px 0 10px;font-weight:600;color:var(--blue);
  background:linear-gradient(90deg,rgba(98,147,253,.13),transparent);
  border-left:3px solid var(--blue);padding:6px 10px;border-radius:0 3px 3px 0;
}
h3{font-size:14.5px;margin:20px 0 8px;color:var(--vio2);font-weight:600}
h4{font-size:13.5px;margin:16px 0 6px;color:var(--fg2);font-weight:600}
p{margin:.7em 0}
a{color:var(--blue);text-decoration:none;border-bottom:1px solid rgba(98,147,253,.3)}
a:hover{color:var(--vio2);border-bottom-color:var(--vio2)}
hr{border:0;border-top:1px solid var(--line);margin:1.6em 0}
code{background:var(--bg3);border:1px solid var(--line);padding:0 5px;border-radius:2px;font:.86em var(--mono);color:var(--fg2)}
pre{background:var(--bg2);border:1px solid var(--line);border-left:3px solid var(--vio);border-radius:0 3px 3px 0;padding:11px 13px;overflow:auto}
pre code{background:none;border:0;padding:0}
img{max-width:100%;border-radius:3px;display:block;margin:13px 0;border:1px solid var(--line)}
blockquote{
  margin:13px 0;padding:9px 13px;border-left:3px solid var(--indigo);
  background:linear-gradient(90deg,rgba(50,44,117,.28),rgba(50,44,117,.06));
  border-radius:0 3px 3px 0;color:var(--fg2);
}
blockquote p{margin:.35em 0}
blockquote em{color:#fff;font-style:italic}
blockquote.warn{border-left-color:var(--hot);background:linear-gradient(90deg,rgba(255,81,47,.13),transparent)}
p.warnp{
  border-left:3px solid var(--hot);background:linear-gradient(90deg,rgba(255,81,47,.13),transparent);
  padding:9px 13px;border-radius:0 3px 3px 0;margin:13px 0;
}
table{border-collapse:collapse;width:100%;margin:14px 0;font-size:13.5px;display:block;overflow-x:auto}
th,td{border:1px solid var(--line);padding:6px 9px;text-align:left;vertical-align:top}
th{background:linear-gradient(180deg,var(--bg3),var(--bg2));color:var(--vio2);font-weight:600;font-size:12.5px}
tr:nth-child(even) td{background:rgba(255,255,255,.014)}
ul,ol{padding-left:22px}
li{margin:.25em 0}
li::marker{color:var(--vio)}

/* карточки уроков — как строки форума */
.cards{display:flex;flex-direction:column;gap:5px}
.card{
  background:var(--bg2);border:1px solid var(--line);border-left:3px solid var(--line2);
  border-radius:0 3px 3px 0;padding:9px 12px;cursor:pointer;transition:all .15s;
}
.card:hover{border-color:var(--line2);border-left-color:var(--vio);background:var(--bg3)}
.card-h{display:flex;gap:9px;align-items:baseline}
.card-t{font-weight:600;flex:1;font-size:14px}
.card-m{font:11px var(--mono);color:var(--fg3);margin-top:4px;display:flex;gap:11px;flex-wrap:wrap}
.badge{font:10px var(--mono);padding:1px 6px;border-radius:2px;background:var(--bg4);color:var(--fg3);border:1px solid var(--line)}
.badge.warn{background:rgba(255,81,47,.14);color:var(--hot);border-color:rgba(255,81,47,.35)}
.badge.hw{background:rgba(147,121,240,.14);color:var(--vio2);border-color:rgba(147,121,240,.35)}

/* шапка урока */
.lhead{border:1px solid var(--line);background:var(--bg2);border-radius:3px;margin-bottom:20px;overflow:hidden}
.lhead::before{
  content:"информация о материале";display:block;
  background:linear-gradient(90deg,var(--indigo),rgba(50,44,117,.25));
  color:var(--fg2);font:10.5px var(--mono);letter-spacing:1px;text-transform:uppercase;
  padding:5px 12px;border-bottom:1px solid var(--line);
}
.lhead-t{font:11.5px/1.75 var(--mono);color:var(--fg3);display:grid;grid-template-columns:auto 1fr;gap:2px 14px;padding:11px 13px 4px}
.lhead-t b{color:var(--vio2);font-weight:400}
.lactions{display:flex;gap:7px;padding:8px 13px 12px;flex-wrap:wrap}
.btn{
  background:var(--bg3);border:1px solid var(--line);color:var(--fg2);
  padding:5px 11px;border-radius:3px;cursor:pointer;font:12px var(--mono);text-decoration:none;transition:all .15s;
}
.btn:hover{border-color:var(--vio);color:#fff;box-shadow:0 0 10px rgba(147,121,240,.3)}
.btn.on{background:rgba(147,121,240,.2);border-color:var(--vio);color:var(--vio2)}

/* термины */
.term{color:var(--vio2);border-bottom:1px dashed rgba(147,121,240,.6);cursor:help}
.term:hover{background:rgba(147,121,240,.16);text-shadow:0 0 10px rgba(147,121,240,.6)}
#tip{
  position:fixed;z-index:60;max-width:330px;background:var(--bg2);color:var(--fg);
  border:1px solid var(--vio);border-radius:3px;padding:8px 11px;font-size:12.5px;line-height:1.5;
  box-shadow:0 8px 30px rgba(0,0,0,.7),0 0 22px rgba(147,121,240,.25);pointer-events:none;
}
#tip b{color:var(--vio2)}
#tip .tip-orig{color:var(--fg3);font:11px var(--mono);display:block;margin-top:2px}
#tip .tip-pit{color:var(--hot);font-size:11.5px;display:block;margin-top:6px}

/* правая панель */
#panel{background:var(--bg2);border-left:1px solid var(--line);overflow:auto;padding:16px 16px 40px;position:relative}
.pclose{position:absolute;top:8px;right:11px;background:none;border:0;color:var(--fg3);font-size:20px;line-height:1;cursor:pointer}
.pclose:hover{color:var(--hot)}
.p-term{font-size:17px;font-weight:700;margin:0 24px 2px 0;color:var(--vio2);text-shadow:0 0 14px rgba(147,121,240,.4)}
.p-orig{color:var(--fg3);font:12px var(--mono);margin-bottom:12px}
.p-sec{margin-top:13px}
.p-sec h5{margin:0 0 4px;font:10px var(--mono);text-transform:uppercase;letter-spacing:1.1px;color:var(--vio);font-weight:400}
.p-pit{border-left:3px solid var(--hot);background:linear-gradient(90deg,rgba(255,81,47,.12),transparent);padding:8px 11px;border-radius:0 3px 3px 0;font-size:13px}
.p-rel{display:flex;flex-wrap:wrap;gap:4px;margin-top:5px}
.p-rel button{background:var(--bg3);border:1px solid var(--line);color:var(--vio2);font:11.5px var(--mono);padding:3px 8px;border-radius:3px;cursor:pointer}
.p-rel button:hover{border-color:var(--vio);box-shadow:0 0 8px rgba(147,121,240,.3)}

.empty{color:var(--fg3);padding:26px 0;font-family:var(--mono)}
.note{font-size:12.5px;color:var(--fg3);margin:6px 0 0}
.grid2{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:6px;margin:14px 0}
.tile{
  background:var(--bg2);border:1px solid var(--line);border-radius:3px;padding:9px 11px;
  border-top:2px solid var(--vio);
}
.tile b{display:block;font-size:21px;font-weight:700;color:var(--vio2);font-family:var(--mono);text-shadow:0 0 14px rgba(147,121,240,.35)}
.tile span{font:11px var(--mono);color:var(--fg3)}

/* ---------------- анимации ---------------- */
@media (prefers-reduced-motion:no-preference){
  .view-in{animation:viewIn .26s cubic-bezier(.22,.9,.3,1) both}
  @keyframes viewIn{from{opacity:0;transform:translateY(7px)}to{opacity:1;transform:none}}
  .cards .card{animation:cardIn .3s cubic-bezier(.22,.9,.3,1) both}
  .cards .card:nth-child(1){animation-delay:.015s} .cards .card:nth-child(2){animation-delay:.035s}
  .cards .card:nth-child(3){animation-delay:.055s} .cards .card:nth-child(4){animation-delay:.075s}
  .cards .card:nth-child(5){animation-delay:.095s} .cards .card:nth-child(n+6){animation-delay:.11s}
  @keyframes cardIn{from{opacity:0;transform:translateX(-6px)}to{opacity:1;transform:none}}
  #panel:not([hidden]){animation:panelIn .24s cubic-bezier(.22,.9,.3,1) both}
  @keyframes panelIn{from{opacity:0;transform:translateX(20px)}to{opacity:1;transform:none}}
  #tip:not([hidden]){animation:tipIn .12s ease-out both}
  @keyframes tipIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}
  .btn:active{transform:translateY(1px)}
  /* Ступенчатое появление: задержку проставляет stagger() в app.js,
     здесь только сама анимация. */
  .rise{animation:riseIn .34s cubic-bezier(.22,.9,.3,1) both}
  @keyframes riseIn{from{opacity:0;transform:translateY(11px) scale(.985)}to{opacity:1;transform:none}}
  .drill:hover{transform:translateY(-2px)}
  .drill-lv::before{animation:glowpulse 3.4s ease-in-out infinite}
}
#readbar{position:fixed;top:0;left:0;height:2px;z-index:70;width:0;transition:width .1s linear;
  background:linear-gradient(90deg,var(--vio),var(--blue));box-shadow:0 0 10px rgba(147,121,240,.8)}

/* ---------------- упражнения ---------------- */
.drill-lv{
  display:flex;align-items:center;gap:9px;margin:26px 0 2px;padding-left:11px;
  position:relative;font-size:17px;
}
.drill-lv::before{
  content:"";position:absolute;left:0;top:4px;bottom:4px;width:3px;background:var(--vio);
  box-shadow:0 0 9px rgba(147,121,240,.75);
}
.drill-lv .tstar{font-size:13px;letter-spacing:0;padding-top:0}
.lv-lead{margin:6px 0 12px;padding-left:11px;max-width:72ch}

.drills{display:grid;grid-template-columns:repeat(auto-fill,minmax(310px,1fr));gap:9px;margin-bottom:8px}
.drill{
  background:var(--bg2);border:1px solid var(--line);border-top:2px solid var(--line2);
  border-radius:0 0 3px 3px;padding:11px 13px 0;display:flex;flex-direction:column;
  transition:border-color .18s,background .18s,transform .18s,box-shadow .18s;
}
.drill.s1{border-top-color:var(--s1)} .drill.s2{border-top-color:var(--s2)} .drill.s3{border-top-color:var(--s3)}
.drill:hover{background:var(--bg3);border-color:var(--line2);box-shadow:0 6px 22px rgba(0,0,0,.45)}
.drill-h{display:flex;gap:9px;align-items:baseline;justify-content:space-between}
.drill-t{font-weight:600;font-size:14.5px;line-height:1.35}
.drill-n{
  font:19px var(--mono);color:var(--vio2);flex:none;
  text-shadow:0 0 12px rgba(147,121,240,.45);transition:color .15s;
}
.drill .card-m{margin-top:6px}
.drill .tag{color:var(--vio2)}
.drill-what{font-size:13px;line-height:1.6;margin:9px 0 0;color:var(--fg)}
/* Проверка — единственный блок, который читают после упражнения,
   поэтому он отбит цветом от описания. */
.drill-check{
  font-size:12.5px;line-height:1.6;margin:9px 0 0;padding:7px 10px;
  background:rgba(98,147,253,.08);border-left:2px solid var(--blue);color:var(--fg2);
}
.drill-check b{color:var(--blue);font-weight:600}
.drill-tool{margin-top:7px;font-family:var(--mono);font-size:11px}
.drill-bar{margin-top:10px}
.drill .lactions{padding:9px 0 12px;margin-top:auto;align-items:center}
.btn.ghost{background:transparent;color:var(--fg3);border-style:dashed;margin-left:auto}
.btn.ghost:hover{color:var(--vio2);border-style:solid}

.planblock{margin-bottom:4px}

/* ---------------- карта курса ---------------- */
.mapwrap{max-width:1000px;margin:0 auto}
.map{width:100%;height:auto;display:block;margin:10px 0 20px;overflow:visible}
/* Связи пунктиром и без наконечников: направление и так читается сверху вниз,
   а стрелки утыкались в рамки и делали схему шумной. */
.edge{
  stroke:#3a3a47;stroke-width:1.5;fill:none;stroke-linecap:round;
  stroke-dasharray:1 6;transition:stroke .2s,stroke-width .2s,opacity .2s;
}
/* Дальние — реже и бледнее, чтобы не спорить с соседними по вертикали. */
.edge.far{stroke-dasharray:1 9;opacity:.5}
.edge.hot{stroke:var(--vio);stroke-width:2.2;opacity:1;filter:drop-shadow(0 0 4px rgba(147,121,240,.8))}
.node{cursor:pointer}
.node rect:first-of-type{fill:var(--bg2);stroke:var(--line2);stroke-width:1.2;transition:all .2s}
.node:hover rect:first-of-type{stroke:var(--vio);fill:var(--bg3);filter:drop-shadow(0 0 8px rgba(147,121,240,.45))}
.node.locked rect:first-of-type{stroke-dasharray:5 4;stroke:#33333d}
.node.locked text{opacity:.45}
.node.notready text{opacity:.68}
.node.full rect:first-of-type{stroke:var(--vio);fill:rgba(50,44,117,.35)}
.node:hover text{opacity:1}
.node text{fill:#fff;font-size:12.5px;font-weight:600;pointer-events:none}
.node .nsub{fill:var(--fg3);font:10.5px var(--mono);font-weight:400}
.pb-bg{fill:#24242c}
.pb-fg{fill:var(--vio);transition:width .5s cubic-bezier(.22,.9,.3,1)}
.maplegend{display:flex;gap:14px;flex-wrap:wrap;font:11px var(--mono);color:var(--fg3);margin:14px 0 4px}
.maplegend i{display:inline-block;width:10px;height:10px;border-radius:2px;margin-right:5px;vertical-align:-1px;background:var(--bg2)}
.lg-full{border:1.5px solid var(--vio);background:rgba(50,44,117,.5)!important}
.lg-open{border:1.5px solid var(--line2)}
.lg-soon{border:1.5px solid var(--line2);opacity:.5}
.lg-empty{border:1.5px dashed #33333d}

/* ---------------- лента активности ---------------- */
.activity{background:var(--bg2);border:1px solid var(--line);border-radius:3px;margin:16px 0 4px;overflow:hidden}
.act-h{
  display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;
  background:linear-gradient(90deg,var(--indigo),rgba(50,44,117,.2));
  padding:6px 12px;border-bottom:1px solid var(--line);font:11px var(--mono);
  text-transform:uppercase;letter-spacing:.9px;color:var(--fg2);
}
.act-m{font:11px var(--mono);color:var(--fg3);text-transform:none;letter-spacing:0}
.act-m b{color:var(--vio2);font-weight:700}
.ascroll{overflow-x:auto;padding:9px 13px 4px}
/* Колонки-недели тянутся долями ширины, а не стоят по 11 px: иначе сетка
   обрывается, не дойдя до правого края рамки. Число колонок проставляет
   activityRibbon() инлайном — оно бывает 52 или 53. minmax оставляет
   горизонтальную прокрутку, если места совсем мало. */
.amons,.agrid{display:grid;gap:3px}
.amons{margin-bottom:4px}
.amon{font:9.5px var(--mono);color:var(--fg3);font-style:normal;white-space:nowrap;overflow:visible;min-width:0}
.acol{display:flex;flex-direction:column;gap:3px;min-width:0}
.acell{
  width:100%;aspect-ratio:1;border-radius:2px;background:#1c1c22;
  border:1px solid #24242c;display:block;transition:transform .12s;
}
/* В подвале-легенде клетки стоят в строке, там доли ширины ни к чему. */
.act-f .acell{width:11px;height:11px;aspect-ratio:auto;flex:none}
.act-hint{margin-left:auto;opacity:.7}
.acell:hover{transform:scale(1.4);z-index:2;position:relative}
.acell.l1{background:#2c2464;border-color:#3a2f80}
.acell.l2{background:#4a3aa8;border-color:#5a48c8}
.acell.l3{background:#7358e0;border-color:#8a6ff0}
.acell.l4{background:var(--vio);border-color:var(--vio2);box-shadow:0 0 8px rgba(147,121,240,.7)}
.acell.lf{background:transparent;border-color:transparent}
.act-f{display:flex;align-items:center;gap:3px;padding:4px 13px 11px;font:10px var(--mono);color:var(--fg3)}
.act-f span:first-child{margin-right:4px} .act-f span:last-child{margin-left:4px}

/* ---------------- оглавление урока ---------------- */
/* minmax(0,1fr), а не 1fr: колонка с «1fr» не может стать уже своего
   содержимого, и один длинный URL без пробелов растягивал урок на четыре
   тысячи пикселей. min-width:0 на детях — та же защита уровнем ниже. */
.lesson-grid{display:grid;grid-template-columns:minmax(0,1fr) 190px;gap:26px;align-items:start;max-width:1000px;margin:0 auto}
.lesson-grid>*{min-width:0}
.toc{position:sticky;top:10px;font-size:12px;border-left:1px solid var(--line);padding-left:11px;max-height:calc(100vh - 50px);overflow:auto}
.toc-h{font:10px var(--mono);text-transform:uppercase;letter-spacing:1.1px;color:var(--vio);margin-bottom:7px}
.toc a{display:block;color:var(--fg3);border:0;padding:3px 0 3px 8px;line-height:1.35;border-left:2px solid transparent;margin-left:-9px}
.toc a:hover{color:var(--fg2)}
.toc a.is-on{color:var(--vio2);border-left-color:var(--vio)}
.toc a.lvl3{padding-left:18px;font-size:11.5px}
@media (max-width:1240px){ .lesson-grid{grid-template-columns:minmax(0,1fr)} .toc{display:none} }

/* ---------------- защита от горизонтального разъезда ----------------
   В уроках 679 «слов» длиннее 80 символов — в основном ссылки на исходники.
   Без переноса такое слово распирает страницу, и текст уезжает вбок.
   anywhere (а не break-word) выбран намеренно: только он уменьшает
   минимальную ширину блока, а значит влияет на расчёт колонок сетки. */
#main{overflow-x:hidden}
#main p,#main li,#main blockquote,#main h1,#main h2,#main h3,#main h4,
#main td,#main th,#main dd,#main figcaption{overflow-wrap:anywhere}
#main a{overflow-wrap:anywhere}
#main img,#main video,#main svg{max-width:100%;height:auto}
/* Широкая таблица прокручивается внутри себя, а не тащит за собой страницу. */
#main table{display:block;width:max-content;max-width:100%;overflow-x:auto}
#main pre{max-width:100%;overflow-x:auto}
#main code{overflow-wrap:anywhere}

/* галерея */
.gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(132px,1fr));gap:6px;margin:13px 0 8px}
.gitem{display:block;border:1px solid var(--line);border-radius:3px;overflow:hidden;background:var(--bg2);line-height:0}
.gitem img{margin:0;border:0;border-radius:0;width:100%;height:104px;object-fit:cover;transition:transform .25s cubic-bezier(.22,.9,.3,1),filter .2s}
.gitem:hover{border-color:var(--vio);box-shadow:0 0 12px rgba(147,121,240,.35)}
.gitem:hover img{transform:scale(1.07);filter:brightness(1.1)}

/* возврат к месту чтения */
.resume{
  display:flex;gap:10px;align-items:center;justify-content:space-between;
  background:linear-gradient(90deg,rgba(50,44,117,.5),rgba(50,44,117,.12));
  border:1px solid var(--line2);border-left:3px solid var(--vio);
  border-radius:0 3px 3px 0;padding:8px 12px;margin:0 0 16px;font-size:12.5px;
}
.resume button{background:var(--bg3);border:1px solid var(--vio);color:var(--vio2);border-radius:3px;padding:3px 9px;cursor:pointer;font:11px var(--mono)}

/* скроллбары */
*::-webkit-scrollbar{width:11px;height:11px}
*::-webkit-scrollbar-track{background:var(--bg)}
*::-webkit-scrollbar-thumb{background:var(--bg4);border:2px solid var(--bg);border-radius:6px}
*::-webkit-scrollbar-thumb:hover{background:var(--indigo)}

::selection{background:rgba(147,121,240,.45);color:#fff}

/* ============ вайб старого веба ============ */

/* CRT-развёртка поверх всего: тонкие горизонтальные полосы + виньетка */
body::after{
  content:"";position:fixed;inset:0;pointer-events:none;z-index:90;
  background:
    repeating-linear-gradient(180deg, rgba(0,0,0,.16) 0 1px, transparent 1px 3px),
    radial-gradient(120% 90% at 50% 45%, transparent 55%, rgba(0,0,0,.42) 100%);
  mix-blend-mode:multiply;opacity:.55;
}

/* прямые углы у всего — как в оригинале жанра */
.card,.tile,.activity,.lhead,.badge,.chip,.navbtn,.btn,.bar,.gitem,.acell,#tip,pre,code,
.filters select,.filters input[type=search],.p-rel button,.tiny,.resume button{border-radius:0}

/* шапка-баннер */
.brand{position:relative;overflow:hidden}
.brand::before{
  content:"";position:absolute;inset:0;z-index:0;opacity:.5;
  background:
    repeating-linear-gradient(90deg, rgba(147,121,240,.18) 0 2px, transparent 2px 5px),
    repeating-linear-gradient(180deg, rgba(0,0,0,.4) 0 1px, transparent 1px 2px),
    linear-gradient(120deg,var(--deep),var(--indigo) 55%,#1a0f3a);
}
.brand-t,.brand-s{position:relative;z-index:1}
.brand-t{animation:glowpulse 3.4s ease-in-out infinite}
@keyframes glowpulse{
  0%,100%{text-shadow:0 0 12px rgba(147,121,240,.5)}
  50%{text-shadow:0 0 20px rgba(147,121,240,.95),0 0 34px rgba(98,147,253,.4)}
}

/* мигание и радуга — из арсенала жанра, но дозированно */
@keyframes blink{50%{opacity:.25}}
@keyframes rainbow{
  0%{color:#ff512f} 20%{color:#ffd23f} 40%{color:#7ee787}
  60%{color:#6293fd} 80%{color:#9379f0} 100%{color:#ff512f}
}
.blink{animation:blink 1.1s steps(1) infinite}
.rainbow{animation:rainbow 4s linear infinite;font-weight:700}

/* цветные префиксы тем перед названием урока */
.pfx{
  font:9.5px/1.5 var(--mono);letter-spacing:.5px;padding:1px 5px;flex:none;
  border:1px solid currentColor;text-transform:uppercase;opacity:.95;
}
.pf-me{color:#c9bcf8} .pf-li{color:#9c91ff} .pf-pe{color:#6293fd} .pf-ko{color:#7ee787}
.pf-an{color:#e0af68} .pf-sv{color:#ffd23f} .pf-fa{color:#ff9e64} .pf-cv{color:#ff79c6}
.pf-ka{color:#8be9fd} .pf-di{color:#bd93f9} .pf-st{color:#a0a8b8} .pf-ra{color:#ff512f}
.pf-l2{color:#50fa7b} .pf-so{color:#8c8c8c} .pf-vo{color:#f1a7fe} .pf-lc{color:#ffb86c}
.pf-sk{color:#8fd7d7}

/* подвал с бейджами */
.footer{
  margin-top:34px;padding:20px 0 10px;border-top:1px solid var(--line);
  display:flex;flex-direction:column;align-items:center;gap:14px;text-align:center;
}
.kao{
  font:20px/1 var(--mono);color:var(--vio2);letter-spacing:2px;
  text-shadow:0 0 18px rgba(147,121,240,.6);
}
.badges{display:flex;flex-wrap:wrap;gap:4px;justify-content:center;max-width:560px}
.b31{display:block;image-rendering:pixelated;transition:transform .12s,filter .12s}
.b31:hover{transform:scale(1.12);filter:brightness(1.25) drop-shadow(0 0 6px rgba(147,121,240,.7));cursor:help}
.fnote{font:10.5px/1.6 var(--mono);color:var(--fg3);max-width:520px;margin:0}

/* ============================================================
   Узкое окно и телефон
   Две ступени: 1100 — исчезает место под третью колонку,
   900 — под боковую. Порог 900 совпадает с проверкой в app.js,
   которая закрывает выдвинутую панель при развороте окна.
   ============================================================ */

/* --- планшет и узкое окно: боковая ещё помещается, карточка термина уже нет --- */
@media (min-width:901px) and (max-width:1100px){
  #shell{position:relative}          /* якорь для карточки, чтобы она легла внутрь рамки */
  #shell.has-panel{grid-template-columns:296px 1fr}
  #panel{
    position:absolute;top:0;right:0;bottom:0;width:min(340px,58%);z-index:50;
    box-shadow:-16px 0 44px rgba(0,0,0,.55);
  }
}

/* ---------------- телефон ---------------- */
@media (max-width:900px){

  /* Размытое видео лежит под окном, а окно теперь во весь экран — видно его
     всё равно не будет, зато греется телефон. */
  #bgvid{display:none}

  /* Окно больше не 4:3 по центру: центрирование оставило бы полосу
     посреди чёрного поля. */
  body{display:block}
  /* Ландшафтная ориентация в сафари иначе раздувает кегль сама. */
  html{-webkit-text-size-adjust:100%}
  #boot{padding:34vh 22px 0;text-align:center}

  /* dvh с запасным vh: на телефоне адресная строка съедает часть vh,
     и низ окна (полоса прогресса в боковой) уезжает под неё. */
  #shell{
    width:100%;
    height:100vh;
    height:100dvh;
    grid-template-columns:100%;
    grid-template-rows:auto minmax(0,1fr);   /* minmax(0,…): иначе #main не сожмётся и появится вторая прокрутка */
    border:0;box-shadow:none;
  }
  #shell.has-panel{grid-template-columns:100%}

  /* ---- шапка ---- */
  #topbar{
    display:flex;align-items:center;gap:6px;
    height:48px;padding:0 6px;
    position:relative;z-index:50;          /* выше выдвижной панели и затемнения */
    background:linear-gradient(180deg,rgba(50,44,117,.92),var(--bg2));
    border-bottom:1px solid var(--line2);
  }
  #menuBtn,#topAcc{
    flex:none;width:42px;height:42px;padding:0;
    display:flex;align-items:center;justify-content:center;
    background:var(--bg3);border:1px solid var(--line);color:var(--fg2);
    border-radius:0;cursor:pointer;
  }
  /* Три полоски: в разметке лежат три пустых <i>, рисовать их нечем, кроме фона. */
  #menuBtn{flex-direction:column;gap:4px}
  #menuBtn i{display:block;width:17px;height:2px;background:currentColor}
  #topAcc{font:17px/1 var(--mono)}
  #menuBtn:active,#topAcc:active{background:var(--bg4)}
  /* Открытая панель — крестик вместо полосок: шаг между полосками 6 px. */
  body.nav-open #menuBtn{border-color:var(--vio);color:var(--vio2)}
  body.nav-open #menuBtn i:nth-child(1){transform:translateY(6px) rotate(45deg)}
  body.nav-open #menuBtn i:nth-child(2){opacity:0}
  body.nav-open #menuBtn i:nth-child(3){transform:translateY(-6px) rotate(-45deg)}
  #topTitle{
    flex:1;min-width:0;text-align:center;
    font:13px/1.2 var(--mono);letter-spacing:.4px;color:var(--fg2);
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  }

  /* ---- боковая: выдвижная панель поверх содержимого ---- */
  /* display не трогаем: показом затемнения управляет атрибут hidden из app.js. */
  #scrim:not([hidden]){display:block}
  #scrim{
    position:fixed;inset:0;z-index:46;
    background:rgba(6,4,14,.62);
    -webkit-backdrop-filter:blur(1.5px);backdrop-filter:blur(1.5px);
  }
  #side{
    position:fixed;left:0;top:48px;z-index:48;
    width:min(84%,320px);
    height:calc(100vh - 48px);
    height:calc(100dvh - 48px);
    border-right:1px solid var(--line2);
    box-shadow:7px 0 34px rgba(0,0,0,.62);
    transform:translateX(-100%);
    visibility:hidden;                      /* убранная панель не должна ловить фокус табом */
    /* Прокручивается вся панель целиком, а не список внутри неё: на экране
       телефона крупные кнопки и фильтры занимают всю высоту, списку уроков
       остаётся 22 px, а нижние блоки просто обрезаются. */
    overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
  }
  #side>*{flex:none}                        /* иначе flex сжимает шапку и фильтры до нечитаемого */
  .sidelist{overflow:visible}
  body.nav-open #side{transform:none;visibility:visible}

  /* ---- навигация и фильтры под палец ---- */
  .brand{padding:11px 13px 10px}
  .nav{gap:6px;padding:10px}
  .navbtn{flex:1 1 calc(50% - 6px);min-height:40px;padding:6px 8px;font-size:13px}
  .filters{gap:9px;padding:11px 10px}
  .fl-row{gap:5px;flex-wrap:wrap}
  .chip{
    flex:1 1 auto;min-height:40px;padding:0 10px;font-size:13px;
    display:flex;align-items:center;justify-content:center;
  }
  /* 16 px, а не 12.5: мобильный сафари сам приближает страницу,
     если поле мельче, и после ввода она остаётся увеличенной. */
  .filters select,.filters input[type=search]{min-height:40px;padding:7px 9px;font-size:16px}
  .ck{min-height:40px;font-size:14px;gap:9px}
  .ck input{width:18px;height:18px;flex:none}
  .thead{min-height:42px;align-items:center;padding:7px 9px}
  .titem{min-height:42px;align-items:center;padding:8px 9px 8px 13px;font-size:13.5px}
  .tstar{padding-top:0}
  .progress-box{padding:11px 13px}
  .tiny{min-height:38px;padding:0 13px;display:inline-flex;align-items:center}

  /* ---- главная колонка ---- */
  #main{padding:14px 13px 56px}
  h1{font-size:20px;margin-bottom:13px}
  h2{font-size:15px;margin:20px 0 9px}
  .lhead-t{padding:10px 11px 4px}
  .lactions{gap:8px;padding:8px 11px 11px}
  .btn,.p-rel button,.resume button{min-height:40px;padding:0 13px;display:inline-flex;align-items:center}
  .card{padding:11px 12px}
  .resume{flex-wrap:wrap;gap:8px}
  .drills{grid-template-columns:minmax(0,1fr)}
  .drill{padding:11px 12px 0}

  /* ---- лента активности ----
     Клетки не должны превращаться в пыль: неделя не уже ~9 px, а лишнее
     уезжает вбок внутри .ascroll — .activity его обрезает, наружу не течёт. */
  .ascroll{padding:9px 10px 6px;overscroll-behavior-x:contain}
  .amons,.agrid{min-width:660px}
  .act-h{padding:6px 10px}
  .act-f{flex-wrap:wrap;padding:4px 10px 10px}
  .act-hint{margin-left:0;flex:1 0 100%}

  /* ---- карта курса ----
     Схема шириной 874 px, вписанная в 334, даёт подписи по 5 px. Поднять
     кегль нельзя — названия узлов и так занимают почти всю ширину рамки,
     полезут друг на друга. Поэтому оставляем читаемый минимум и прокрутку. */
  .mapwrap{overflow-x:auto;overscroll-behavior-x:contain}
  .map{min-width:720px;margin:8px 0 16px}
  .maplegend{gap:8px 14px;margin:12px 0 4px}

  /* ---- карточка термина: 372 px некуда положить, разворачиваем на экран ---- */
  #panel{
    position:fixed;inset:0;z-index:60;
    border-left:0;border-top:2px solid var(--vio);
    padding:46px 14px 40px;
  }
  .pclose{
    top:3px;right:5px;width:40px;height:40px;font-size:26px;
    display:flex;align-items:center;justify-content:center;
  }

  /* Подсказка шире экрана не влезает; положение по горизонтали
     дожимает showTip() в app.js. */
  #tip{max-width:min(330px,calc(100vw - 22px));font-size:13px}

  /* ---- подвал ---- */
  .footer{margin-top:26px;padding:16px 0 8px;gap:11px}
  .badges{max-width:100%}

  /* Полосы развёртки на плотном экране телефона превращаются в муар
     и мешают читать мелкий текст: оставляем только слабую виньетку. */
  body::after{
    background:radial-gradient(130% 92% at 50% 45%, transparent 62%, rgba(0,0,0,.38) 100%);
    opacity:.4;
  }
}

@media (max-width:900px) and (prefers-reduced-motion:no-preference){
  /* visibility переключается без задержки при открытии и с задержкой при
     закрытии — иначе панель пропадала бы, не доехав до края. */
  #side{transition:transform .22s cubic-bezier(.22,.9,.3,1),visibility 0s linear .22s}
  body.nav-open #side{transition:transform .22s cubic-bezier(.22,.9,.3,1),visibility 0s}
  #menuBtn i{transition:transform .2s,opacity .15s}
  #scrim:not([hidden]){animation:scrimIn .18s ease-out both}
  @keyframes scrimIn{from{opacity:0}to{opacity:1}}
  /* Карточка термина на телефоне занимает экран целиком — сдвиг вбок
     от неё читается как рывок, снизу вверх выглядит как лист. */
  #panel:not([hidden]){animation:panelUp .22s cubic-bezier(.22,.9,.3,1) both}
  @keyframes panelUp{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
}
