/* style-09-dossier-chat.css — часть бывшего style.css (распил 22.10.2026): досье, тумблеры, личка, чат, родительский канал.
   Файлы style-NN-*.css — ОДИН каскад: index.html подключает их подряд и по номерам, порядок значим
   (правило ниже по каскаду перебивает равное выше). Стережёт tools/check.js. */
  /* ---- ДОСЬЕ (blox23 #4): приватная шторка учителя — журнал по датам + цветные ярлыки.
     Вставляем/убираем один узел (никогда не перестраиваем список целиком) — прокрутка шторки
     не прыгает. Поля ≥16px, иначе Safari зумит страницу (lingo-ui rule 3). */
  .dsheet{max-width:560px}
  .dprivate{font-size:var(--fs-sm);color:var(--muted);margin:-4px 0 12px}
  /* авто-сводка группы: НЕ журнал (пересчитывается при каждом открытии) — отделена рамкой+фоном */
  .dsummary:empty{display:none}
  .dsummary{border:1px solid var(--line-soft);border-radius:var(--r-md);background:var(--surface-2);
    padding:11px 13px;margin-bottom:14px}
  .dsum-head{font-size:var(--fs-xs);font-weight:700;color:var(--muted);margin-bottom:7px;
    display:flex;align-items:center;gap:5px}
  .dsum-verdict{font-size:var(--fs-md);margin-bottom:8px}
  .dsum-verdict.v-good{color:var(--ok-ink)}
  .dsum-verdict.v-mid{color:var(--gold-ink)}
  .dsum-verdict.v-poor{color:var(--alert-ink)}
  .dsum-verdict.v-progress{color:var(--ink)}   /* предстоящий урок «в процессе» — нейтрально, не тревожно */
  .dsum-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
  .dsum-list li{font-size:var(--fs-sm);color:var(--ink);line-height:1.35;
    padding-left:14px;position:relative;overflow-wrap:anywhere}
  .dsum-list li::before{content:'•';position:absolute;left:2px;color:var(--muted)}
  .dsum-dim{color:var(--muted)}
  .dsum-empty{font-size:var(--fs-sm);color:var(--muted)}
  .dtags{display:flex;flex-wrap:wrap;gap:7px;margin-bottom:10px}
  .dtags:empty{display:none}
  .dtag{display:inline-flex;align-items:center;gap:5px;font-size:var(--fs-sm);font-weight:700;
    padding:4px 6px 4px 12px;border-radius:var(--r-pill);border:1px solid;overflow-wrap:anywhere}
  .dtag .dtag-x{border:none;background:none;cursor:pointer;font-size:var(--ic-sm);line-height:1;
    color:inherit;opacity:.55;padding:0 2px}
  @media (hover:hover){.dtag .dtag-x:hover{opacity:1}}
  .dtag.c0{background:var(--fill-soft);border-color:var(--line-mid);color:var(--ink)}
  .dtag.c1{background:var(--ok-tint);border-color:var(--ok-line);color:var(--ok-ink)}
  .dtag.c2{background:var(--gold-tint);border-color:var(--gold-line);color:var(--gold-ink)}
  .dtag.c3{background:var(--accent-tint);border-color:var(--accent-deep);color:var(--accent-dark)}
  .dtag.c4{background:var(--alert-tint);border-color:var(--alert-line);color:var(--alert-ink)}
  .dtagadd{display:flex;gap:8px;margin-bottom:16px}
  .dtagadd input{flex:1;min-width:0;font-size:var(--fs-input);font-family:inherit;
    border:1px solid var(--line);border-radius:var(--r-sm);padding:9px 12px;color:var(--ink)}
  .dtagadd input:focus{outline:none;border-color:var(--accent-deep)}
  .dtagadd .btn-ghost{width:auto;flex:0 0 auto;margin-top:0}
  .dnew{margin-bottom:16px}
  .dnew textarea{width:100%;box-sizing:border-box;font-size:var(--fs-input);font-family:inherit;
    min-height:80px;resize:vertical;border:1px solid var(--line);border-radius:var(--r-sm);
    padding:10px 12px;color:var(--ink);margin-bottom:8px}
  .dnew textarea:focus{outline:none;border-color:var(--accent-deep)}
  .dnew .btn-pub{width:100%}
  .djournal{display:flex;flex-direction:column;gap:10px}
  .dentry{border:1px solid var(--line-soft);border-radius:var(--r-md);padding:10px 12px;background:var(--surface-2)}
  .dwhen{display:flex;align-items:center;justify-content:space-between;
    font-size:var(--fs-xs);font-weight:700;color:var(--muted);margin-bottom:5px}
  .dentry-x{border:none;background:none;cursor:pointer;color:var(--muted);font-size:var(--ic-sm);
    line-height:1;padding:0 2px;opacity:.6}
  @media (hover:hover){.dentry-x:hover{opacity:1;color:var(--alert-ink)}}
  /* ЗАПИСЬ ДОСЬЕ — тоже читаемый текст (blox52 #6): учитель пишет её предложениями и потом
     перечитывает. Судья её не называл, но оставить её жирной значило бы завести ровно ту
     разноголосицу, которую эта пачка и убирает. */
  .dbody{font-size:var(--fs-md);line-height:1.45;color:var(--ink);white-space:pre-wrap;overflow-wrap:anywhere;
    font-weight:var(--fw-read);text-wrap:pretty}
  /* blox43 #11 — личка на широком экране (ПК/планшет): таски 60% и ВСТРОЕННОЕ досье ученика
     (с blox83 #1 досье слева, таски справа — порядок задан разметкой в renderStudentReview). Колонка досье липнет к верху и прокручивается ВНУТРИ себя (длинный журнал не растит
     страницу — lingo-ui rule 3: растущий ребёнок ограничен своей зоной прокрутки).
     Липнет НЕ к нулю, а под шапку (--hdr-h): плашка sticky и лежит выше по z-index, поэтому при
     top:10px верх досье («Досье · Имя», «Личные заметки…») уезжал ЗА неё и было видно только низ
     (владелец). По той же причине из высоты вычитается и высота шапки — иначе низ колонки уходил
     бы за нижний край экрана ровно на эти 66px. */
  @media(min-width:761px){
    .sr-split{display:flex;gap:18px;align-items:flex-start}
    .sr-split .sr-main{flex:3;min-width:0}
    .sr-split .sr-side{flex:2;min-width:0;position:sticky;top:calc(var(--hdr-h) + 10px);
      max-height:calc(100vh - var(--hdr-h) - 20px);overflow:auto;
      background:var(--card);border:1px solid var(--line-soft);border-radius:var(--r-md);
      box-shadow:var(--sheet-1);padding:14px 16px;box-sizing:border-box}
    .sr-side-h{display:flex;align-items:center;gap:6px;font-weight:800;margin-bottom:10px}
  }
  /* blox43 #11 — монитор: тумблер Notes/Tasks по центру ВЕРХА левой панели. Абсолютная позиция —
     одна и та же точка в обоих режимах и на любом варианте панели (лист/edge/досье), тумблер не
     прыгает при переключении. Центруем НЕ через transform: hover/active ставят свой transform
     (лифт -1px, press scale) и затирали бы translateX(-50%) — на наведении прыгало вправо на
     пол-ширины (владелец, blox43 #11). left/right:0 + width:max-content + margin auto центруют
     без transform.
     blox53 #6 — ЭТО БОЛЬШЕ НЕ ПИЛЮЛЯ. Была кнопка-капсула с одним словом (и слово говорило, куда
     переключит, — по нему нельзя было прочесть, где ты сейчас). Стало: два слова через слеш,
     первое приподнято, второе приспущено, под словом ТЕКУЩЕГО режима — та же полоска, что под
     выбранным чипом группы (.gind: 3px, --accent-ink). Ни рамки, ни заливки, ни скруглений. */
  .opane{position:relative}
  /* абсолют остался ТОЛЬКО у панели-края: шапки у неё нет, вставать тумблеру некуда (см. ниже
     padding-top:56px). На всех прочих панелях он живёт средней колонкой шапки — в потоке.
     top:12px — это padding самой панели, то есть РОВНО тот же уровень, с которого начинается
     шапка у панели-листа. Иначе переключение Notes на панели-крае (край → досье, у досье шапка
     есть) двигало бы тумблер на 6px по вертикали — ассерт «тумблер на месте ±2px» это и поймал. */
  .opane > .onotes{position:absolute;top:12px;left:0;right:0;margin-left:auto;margin-right:auto;
    width:max-content;max-width:calc(100% - 24px);z-index:2}
  /* САМ ВИД тумблера живёт БЕЗ .opane — иначе он не переиспользуем. blox57 #2 поставил такой же
     в шапку окна «из учебника» («Список / Страница»), и запертый в мониторе вид пришлось бы
     копировать вторым экземпляром — ровно то, из-за чего платформа и расползается (правило «один
     элемент — один класс»). Панельное осталось панельным: место (.opane > .onotes), метка
     загрузки (.busy) и резерв строки у панели-края — ниже. */
  .onotes{
    display:flex;align-items:center;justify-content:center;gap:5px;
    min-height:44px;box-sizing:border-box;   /* G5: палец попадает по тумблеру целиком */
    border:none;background:none;box-shadow:none;padding:0 8px;cursor:pointer;
    font-family:inherit;font-size:var(--fs-sm);line-height:1.1}
  .onotes .onw{position:relative;font-weight:800;color:var(--muted);padding:0 2px 6px;
    transition:color var(--t) var(--ease)}
  /* зона нажатия КАЖДОГО слова — во всю высоту тумблера (44px), хотя само слово ростом со строку:
     без неё палец попадал бы в 20px текста (G5). Невидимая, только ловит клик; слова разведены
     слешем, поэтому зоны не перекрываются. */
  .onotes .onw::before{content:"";position:absolute;inset:-14px -5px}
  .onotes .onw.up{transform:translateY(-4px)}   /* первое слово приподнято */
  .onotes .onw.dn{transform:translateY(4px)}    /* второе приспущено */
  .onotes .onsl{color:var(--faint);font-weight:700}
  .onotes .onw.on{color:var(--ink)}
  /* подчёркивание активного слова — тот же голос, что у выбранной группы (blox52 #12) */
  .onotes .onw.on::after{content:"";position:absolute;left:0;right:0;bottom:0;height:3px;
    border-radius:var(--r-2xs);background:var(--accent-ink)}
  @media (hover:hover){.onotes .onw:not(.on):hover{color:var(--ink)}}
  .opane .onotes.busy{opacity:.55}   /* досье грузится, панель ещё прежняя — клик не «провалился» */
  /* Панель-КРАЙ — единственная без шапки, поэтому тумблеру негде стоять: на телефоне такая панель
     схлопывается до высоты своей строки (43px), и тумблер ложится ровно на текст «раньше
     занятий не было» — он полностью закрыт (владелец, blox47 #3). Резервируем ему строку сверху,
     ту самую роль, которую у остальных панелей играет .opane-h{min-height:44px}. `:has` — чтобы
     у края БЕЗ тумблера (правый, «край расписания») отступ не появлялся. */
  .opane.edge:has(.onotes){padding-top:calc(57px - var(--pane-bw))}   /* 56 + волосок; за вычетом рамки — blox84 #4 */
  /* тумблер ростом 44px (touch-target, G5) должен ВЛЕЗАТЬ в шапку, иначе свисает на контент (G9);
     запас одинаковый у обеих панелей — их шапки остаются одной высоты */
  .opane-h{min-height:44px}
  /* ...и вот тут запас переставал быть одинаковым. box-sizing глобально border-box (theme.css),
     то есть min-height считается ПО ВНЕШНЕЙ кромке: шапка БЕЗ тумблера садилась ровно в 44px
     (внутри остаётся 37px — даты и подписи хватало), а шапка С тумблером не могла: сам тумблер
     ростом 44px, и к нему прибавлялись padding-bottom:6px и линейка 1px — итого 51px. С blox53 #6
     тумблер стоит В ПОТОКЕ шапки (раньше лежал абсолютом и высоту не менял), поэтому эти 7px
     достались только ЛЕВОЙ панели: на мониторе панели стоят двумя колонками, и ВСЁ содержимое
     левой — плашка плейлиста, линейка шапки, лист — опускалось на 7px ниже своего близнеца
     справа (замер по всем группам: расходились 26 из 30; совпадали лишь те, где справа стояла
     двухстрочная дата с подписью «выдано · сдач ещё нет» и добирала те же 51px).
     Резервируем строку тумблера у ОБЕИХ шапок — 44px содержимого ПЛЮС своя отбивка.
     Только на мониторе: на телефоне панели идут одна под другой (.otwo column-reverse), ровнять
     нечего, а тумблер там и так уходит на свою строку и делает шапку выше. */
  /* blox84 #7 — у шапки листа плашка-дата стоит на линии 44-пиксельных кнопок (7 + 30), и под ней
     подпись «выдано · сдач ещё нет» (2 + 16): 55px содержимого. Тумблер (44) теперь ниже этой строки,
     поэтому резерв берём по шапке с подписью — иначе лист с подписью снова опускается ниже соседа. */
  @media(min-width:761px){ .opane-h{min-height:calc(7px + 30px + 2px + 16px + 6px + 1px)} }
  .opane.notes .opane-body{display:block}   /* досье — колонкой, а не рядом «таски+ростер» */
  .reviewbody{margin-bottom:12px;display:flex;flex-direction:column;gap:10px}
  .cell.review{cursor:pointer;outline:2px solid rgba(73,54,87,.14)}
  /* teacher HOLLOW cell: white fill, TYPE-colour border, green corner badge (dot -> check) */
  .cell.hollow{background:var(--card);border:2px solid var(--line);position:relative;color:var(--ink)}
  .cell.hollow .ccount{opacity:.75;font-size:var(--fs-sm)}
  /* Угловой значок. Состояния сдачи/открытия он больше НЕ показывает (2026-08-17): в личке это
     дублировало чипы, которые говорят то же словами. Остался один носитель — «снят» (.ret). */
  .bdg{position:absolute;right:-5px;bottom:-5px;min-width:18px;height:18px;border-radius:var(--r-xs);
    background:var(--ok-tint);color:var(--green);font-size:var(--fs-xs);line-height:18px;text-align:center;
    font-weight:800;box-shadow:0 1px 3px rgba(var(--sh-rgb),.28);padding:0 2px}
  /* «снят» — ФАКТ, не тревога (blox52 #11): тот же тинтовый рецепт, что у близнеца .oarch
     на мониторе; сплошная красная заливка ушла к настоящим тревогам (реестр RED_OK). */
  .bdg.ret{background:var(--alert-fill);color:var(--alert-ink)}
  /* clickable student name -> opens that kid's individual homework screen */
  td.name.slink{cursor:pointer}
  @media (hover:hover){td.name.slink:hover{color:var(--accent-dark)}}
  td.name .schev{color:var(--muted);font-weight:700}

  /* teacher: one kid's homework — review cards (white, TYPE-colour left stripe) */
  .srlist{display:flex;flex-direction:column;gap:10px}
  /* blox83 #3 — ЗАПАС ПОД ПОСЛЕДНЕЙ КАРТОЧКОЙ ЛИЧКИ. Когда в личке остались только сдаваемые таски,
     страница стала короткой, и сжатие нижней карточки (поставленный знак учителя уходит на плашку
     Check — ряд из пяти знаков исчезает, −52px; Approve убирает ряд кнопок) укорачивало саму
     страницу: браузер подтягивал прокрутку вверх, и экран прыгал из-под пальца (проба blox64 #6).
     Полэкрана пустоты под списком — больше любого такого сжатия, поэтому прокрутке некуда
     упираться. */
  .srlist::after{content:'';display:block;height:50vh;flex:none}
  /* blox58 #3 — блок «Stats» в личке: те же плитки .pstat, что у родителя. Кнопка-раскрывашка
     живёт в .toolbar рядом с Feedback, тело — здесь, МЕЖДУ панелью и сводкой занятия: раскрытые
     плитки стоят вплотную к своей кнопке и сдвигают сводку вниз. Отступы висят на .srpar-body, а
     не на обёртке: у скрытого тела (display:none) их нет вовсе, и свёрнутый блок не оставляет
     между панелью и сводкой лишнего зазора. */
  .srpar{margin:0}
  .srpar-body{margin:0 0 12px}
  .srpar-note{font-size:var(--fs-xs);font-weight:700;color:var(--muted);margin-bottom:8px;max-width:60ch}
  .srpar-chev{transition:transform var(--t) var(--ease)}
  .srpar-btn[aria-expanded="true"] .srpar-chev{transform:rotate(180deg)}
  /* ЛИЧКА НА ТЕЛЕФОНЕ: «Досье» · «Stats» · «Feedback» — один ряд равными долями (flex:1 1 0 даёт
     одинаковую ширину независимо от длины подписи), отступы сжаты ручкой движка --btn-px, как у
     ряда чипов ученика (.toolbar.stbar). «Принять всё» — главное действие, ему своя строка во всю
     ширину: четвёртой кнопкой в ряду оно бы раздавило остальные три. */
  @media (max-width:430px){
    .toolbar.srbar{gap:6px;width:100%}
    .toolbar.srbar>.btn-ghost,.toolbar.srbar>.btn-fb{--btn-px:8px;flex:1 1 0;min-width:0;white-space:nowrap}
    .toolbar.srbar>.btn{flex:1 1 100%}
  }
  .srcard{border-radius:var(--r-md);padding:14px 16px 14px 25px}
  /* ПРИНЯТО = ЗЕЛЁНОЕ, как у близнеца (blox52 #15). Стояло opacity:.62 — принятая работа
     выглядела ВЫКЛЮЧЕННОЙ, при том что тот же предмет у ученика (.rect.done) зелёный: успех
     не бывает полупрозрачным. Рецепт близнеца целиком: селадоновая заливка + зелёный рельс,
     тень оседает до обрезного края — карточка тихо отступает, но остаётся листом. Замер
     контраста на --ok-tint (06.09.2026): --ink 10.9/12.3/10.2 · --muted 6.1/5.6/4.9
     (база/синие/ночь) — AA держится; при opacity:.62 всё это глушилось разом.
     Реестр GREEN_OK (tools/check.js) стережёт СПЛОШНОЙ зелёный (--ok-solid/--grad-accept
     заливкой); тинт состояния --ok-tint — вне реестра сознательно, как и сам .rect.done. */
  .srcard.acc{background:var(--ok-tint);--rail-eff:var(--ok-line);box-shadow:var(--sheet-edge)}
  .srcard.acc .srtitle{color:var(--muted)}
  .srcard .srtitle{font-weight:800;font-size:var(--fs-md);padding-right:28px;overflow-wrap:anywhere}
  .srcard .srsub{display:flex;align-items:center;flex-wrap:wrap;gap:6px;margin-top:4px;
    font-size:var(--fs-xs);font-weight:700;color:var(--muted)}
  .srcard .srstatus{font-size:var(--fs-sm);color:var(--muted);font-weight:600;margin-top:5px;
    display:flex;flex-wrap:wrap;gap:6px;align-items:center}
  /* blox30 #2 — индикаторы таска в личке: каждый факт своей плашкой, все видны одновременно
     (открыл · прослушал N · статус сдачи). Цвет = смысл (роль-токены, не сырые лестницы). */
  .srind{display:inline-flex;align-items:center;gap:4px;font-size:var(--fs-xs);font-weight:700;
    padding:2px 9px;border-radius:var(--r-lg);border:1px solid var(--line);
    background:var(--surface);color:var(--muted-strong);white-space:nowrap}
  .srind svg{width:13px;height:13px}
  .srind.op{background:var(--accent-tint);color:var(--accent-ink);border-color:var(--accent-line)}
  .srind.sok{background:var(--ok-tint);color:var(--ok-ink);border-color:var(--ok-line)}
  /* «сдал — на проверке» — та же ОЧЕРЕДЬ РАБОТЫ, что и бейдж .rrev.pend («Check N») в обзоре
     группы (blox52 #11): ребёнок сделал своё, действовать учителю. Значит и красится так же —
     якорь схемы под белым текстом, а не тревожный красный тинт. Один смысл — один цвет. */
  .srind.spend{background:var(--anchor);color:var(--on-dark);border-color:var(--anchor)}
  .srind.sret{background:var(--draft-tint);color:var(--draft-ink);border-color:var(--draft-line)}
  /* Два «не»-состояния — красноватые, но приглушённые: это не очередь работы (та ушла в якорь
     схемы у «на проверке»), а отсутствие события. Поэтому обе плашки полупрозрачные, а
     «не открывал» (ребёнок даже не заглянул) насыщеннее «не сдавал» (заглянул, но не прислал)
     — фоном на ступень темнее и меньшей прозрачностью. */
  .srind.no{background:var(--alert-fill);color:var(--alert-ink);border-color:var(--alert-line);opacity:.85}
  /* blox80 #3 — клетки файлов многофайлового задания: клетка = аудио/видео файл, зелёная = включал */
  .srind.srfiles{gap:6px;padding-left:7px}
  .srind .srdots{display:inline-flex;gap:3px}
  .srind .srdots i{min-width:18px;height:18px;padding:0 3px;box-sizing:border-box;border-radius:var(--r-xs);display:inline-grid;
    place-items:center;font-style:normal;font-size:var(--fs-2xs);font-weight:800;font-variant-numeric:tabular-nums;
    background:var(--surface-2);color:var(--muted);border:1px solid var(--line-soft)}
  .srind .srdots i.ok{background:var(--ok-tint);color:var(--ok-ink);border-color:var(--ok-line)}
  .srind.sno{background:var(--alert-tint);color:var(--alert-ink);border-color:var(--alert-line);opacity:.65}
  .srcard .srattach{margin:10px 0}
  /* blox26 #3 — инлайновые стили img/audio/video убраны: сдача теперь рендерится сущностью .fileent
     (см. выше), а не голым медиа в потоке. */
  .srcard .srnote{font-size:var(--fs-sm);background:var(--surface);border-radius:var(--r-xs);padding:6px 10px;margin-top:8px}
  /* 08.10.2026 — комментарий учителя у ПРИНЯТОЙ работы стоит вместо «Approve» и жмётся: открывает поле
     похвалы с текущим текстом. Объём (рамка + тень) говорит «это кнопка», а не просто строка. */
  .srcard .srcom-edit{display:block;width:100%;text-align:left;font:inherit;font-size:var(--fs-sm);color:inherit;
    cursor:pointer;border:1px solid var(--line);box-shadow:var(--plank);padding:9px 12px;min-height:40px}
  .srcard .srcom-edit:active{box-shadow:var(--plank-flat);transform:translateY(1px)}
  /* blox73 #10 — главы книги в карточке проверки: блок на присланную главу, у каждой свой ряд кнопок */
  .srcard .srbook{display:flex;flex-direction:column;gap:8px;margin-top:10px}
  .srcard .srch{border:1px solid var(--line-soft);border-radius:var(--r-sm);padding:8px 10px;background:var(--card)}
  .srcard .srch .srattach{margin:8px 0 0}
  /* blox84 #3 — главы РАЗДЕЛЕНЫ ЧЁРНОЙ ПОЛОСОЙ (владелец): серые рамки соседних глав сливались, и
     где кончается одна глава и начинается другая, глаз искал по номеру. Полоса — в середине зазора
     между главами (зазор 8 + отступ 8 = 16, полоса 2px на 7px от каждой), цвет --ink-strong:
     чёрный в светлых схемах, белый в тёмной — «громкая линия» в любой. */
  .srcard .srbook>.srch+.srch{position:relative;margin-top:8px}
  .srcard .srbook>.srch+.srch::before{content:"";position:absolute;left:-1px;right:-1px;top:-10px;height:2px;
    border-radius:var(--r-2xs);background:var(--ink-strong)}
  /* blox82 #2 — ПРИНЯТАЯ ГЛАВА блекнет, как принятая карточка (.srcard.acc): зелёная подложка, тихое
     название, плашка сдачи без акцента (правило в style-02, рядом с .srcard.acc .fileent--check) */
  .srcard .srch.acc{background:var(--ok-tint);border-color:var(--ok-line)}
  .srcard .srch.acc .srch-t{color:var(--muted)}
  .srcard .srch-h{display:flex;align-items:center;flex-wrap:wrap;gap:6px 8px}
  .srcard .srch-n{min-width:22px;height:22px;padding:0 4px;display:inline-grid;place-items:center;border-radius:var(--r-xs);
    background:var(--gold);color:var(--on-gold);font-size:var(--fs-sm);font-weight:800}
  .srcard .srch-t{font-weight:700;flex:1 1 auto;min-width:0}
  /* prior (pre-edit) submission version, kept for old+new review */
  .srcard .srhist{margin-top:10px;border:1px dashed var(--line);border-radius:var(--r-sm);padding:8px 10px;background:var(--surface-2)}
  .srcard .srhist-h{font-size:var(--fs-xs);font-weight:700;color:var(--faint);margin-bottom:6px}
  .srcard .srhist-item{margin-bottom:6px}
  /* ПОДДЕЛЬНОГО КУРСИВА НЕТ (blox52 #3, п.3). Здесь стоял font-style:italic, но у Onest курсивного
     начертания не существует (см. fonts/onest.css — оба @font-face объявлены font-style:normal),
     поэтому браузер рисовал ОБЛИК: наклонял обычные буквы сдвигом. Это типографский брак —
     у настоящего курсива другие формы букв, а не наклон. Смысл «это не сдача, а самоотметка»
     несут те же два признака, что и раньше и без наклона: кегль на ступень мельче и приглушённый
     тон. */
  .srcard .srmuted{font-size:var(--fs-sm);color:var(--faint)}
  .srcard .srlink{display:inline-block;background:var(--accent-tint);border:1px solid var(--line);color:var(--accent-dark);
    text-decoration:none;border-radius:var(--r-sm);padding:8px 14px;font-weight:700;font-size:var(--fs-sm)}
  .srcard .sractions{display:flex;gap:8px;margin-top:10px;flex-wrap:wrap}
  .srcard .sractions .btn,.srcard .sractions .btn-ghost{flex:0 0 auto}
  .srcard .sractions .ret{margin-left:auto}   /* blox81 #4 — «Decline» у правого края карточки, «Approve» слева */
  .srcard textarea{border:1px solid var(--line);border-radius:var(--r-sm);padding:9px 12px;font-size:var(--fs-input);
    width:100%;font-family:inherit;min-height:54px}
  .srcard .bdg{top:12px;right:12px;bottom:auto;left:auto}
  .locknote{background:var(--alert-tint);border:1px solid var(--alert-line);border-radius:var(--r-md);padding:11px 14px;
    font-size:var(--fs-sm);color:var(--alert-ink);margin:6px 0 12px;font-weight:600}

  /* group chat */
  .msgs{display:flex;flex-direction:column;gap:8px;min-height:240px;max-height:60vh;overflow:auto;
    background:var(--card);border-radius:var(--r-md);padding:12px;box-shadow:var(--sheet-1);margin-bottom:10px}
  /* blox52 #16 п.5 — пустой чат без бумажной коробки: скин снят, ГАБАРИТЫ прежние (min-height
     остаётся), чтобы строка ввода не сдвинулась при появлении первого сообщения. Ставится/
     снимается в paintFeed (chat-feed.js) — общий для всех трёх чатов. */
  .msgs.blank{background:none;box-shadow:none}
  /* записка пустого чата: тихая строка слева, НЕ .empty (та — роль «ожидание», по центру).
     Тон --on-bg, а не --faint: без коробки записка лежит на СТОЛЕ, где --faint даёт 1.9:1
     и исчезает (замер blox51 #2 — любой текст вне карточки берёт --on-bg). */
  .msgs .chat-note{color:var(--on-bg);font-size:var(--fs-md);padding:2px 2px;text-align:left}
  .msg-row{display:flex}
  .msg-row.mine{justify-content:flex-end}
  .bubble{max-width:80%;background:var(--surface);border-radius:var(--r-md);padding:8px 12px}
  .msg-row.mine .bubble{background:var(--accent-fill)}
  .bubble .who{font-size:var(--fs-2xs);font-weight:800;color:var(--accent-dark);margin-bottom:2px;word-break:break-word}
  /* СООБЩЕНИЕ В ЧАТЕ — книжный вес (blox52 #6). Правило одно на все три ленты (детский чат,
     родительский канал, учительская): пузырь рисует общий bubbleHTML из chat-feed.js.
     Ник .who рядом остаётся 800 — он подпись, а не речь. Переносов нет: в детском чате пишут
     по-английски (это правило группы), русский словарь резал бы чужие слова. */
  .bubble .txt{font-size:var(--fs-md);white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere;
    font-weight:var(--fw-read);text-wrap:pretty}
  .bubble .time{font-size:var(--fs-2xs);color:var(--muted);margin-top:3px;text-align:right}
  /* blox40 #1 — «English only, my friend 😉»: ответ на заблокированную кириллицу. Место под строку
     держится ВСЕГДА (visibility), чтобы появление подсказки не сдвигало ленту и строку ввода. */
  .chat-eo{visibility:hidden;opacity:0;min-height:18px;margin:0 0 6px;padding:0 4px;
    font-size:var(--fs-sm);font-weight:700;color:var(--accent-dark);
    transition:opacity var(--t) var(--ease)}
  .chat-eo.on{visibility:visible;opacity:1}
  .chatbar{display:flex;gap:8px}
  /* страница Chats (blox32 #2): у встроенной панели родит.-канала первый .dprivate без верх. отступа */
  .chats-page>.dprivate:first-child{margin-top:0}
  /* min-width:0 обязателен: без него поле в flex-строке не сжимается уже своей «родной» ширины
     и распирает строку за правый край экрана (blox11 #3) */
  .chatbar input{flex:1;min-width:0;border:1px solid var(--line);border-radius:var(--r-md);padding:11px 14px;font-size:var(--fs-md)}
  /* width:auto перебивает «.sheet .btn-primary{width:100%}» (style-08-modals.css): в шторке родит.-чата
     эта кнопка «отправить» иначе растягивается на всю строку и давит поле ввода (blox23 #3 fix) */
  .chatbar .btn-primary{padding:11px 16px;flex:0 0 auto;width:auto}

  /* blox32 #2 — кружок-счётчик непрочитанных в углу кнопки/таба. ОДИН класс на все места (кнопка
     «Chats» учителя, «Чат группы» ученика, табы страницы Chats). pointer-events:none — клик проходит
     сквозь кружок на кнопку. Кольцо --card отделяет от фона кнопки.
     blox52 #11: заливка — якорь схемы, не красный. Непрочитанное сообщение — очередь («есть что
     прочитать»), а не провал; красный счётчик был одной из «семи заливок пожара» на мониторе. */
  /* z-index:1 — индикатор поверх волны касания (.ripple-box лежит на 0) */
  .chatdot{position:absolute;z-index:1;top:-7px;right:-7px;min-width:17px;height:17px;padding:0 4px;
    border-radius:var(--r-sm);background:var(--anchor);color:var(--on-dark);font-size:var(--fs-2xs);font-weight:800;
    line-height:17px;text-align:center;box-shadow:0 0 0 2px var(--card);pointer-events:none}
  #ochat,#schat,#oannc,.chats-tabs button{position:relative}
  /* blox35 #1 — тортик в том же углу, что и счётчик непрочитанных. Ни заливки, ни белого кольца:
     иконка цветная сама, а кружок-подложка (нужный цифре на красном) только сжимал бы рисунок —
     на 17px свечки в нём превращались в штрихи. Значок висит прямо на углу кнопки. */
  .chatdot--cake{background:none;box-shadow:none;min-width:0;width:auto;height:auto;padding:0;
    top:-9px;right:-7px;line-height:0}
  .chatdot--cake .ic{width:20px;height:20px}
  /* системный 🎂 (техника Apple) вместо нашей иконки: он ТЕКСТ, поэтому размер задаётся кеглем,
     а не width/height. Кегли подобраны так, чтобы оба варианта занимали одинаковое место. */
  .chatdot--cake .cakemoji{font-size:var(--ic-md);line-height:1;display:block}
  .nday .ncake .cakemoji{font-size:var(--ic-sm);line-height:1;display:block}
  .chats-h{margin-bottom:12px}
  /* детский чат-таб — радужный (как playlist), всегда, чтобы не промахнуться мимо взрослых тредов */
  .chats-tabs button.tab-rainbow,.chats-tabs button.tab-rainbow.on{
    background:var(--grad-playlist);color:var(--ink-strong)}

  /* ===== PARENT CHANNEL (blox23 #3) — poll cards + teacher's reschedule form ===== */
  .pcsheet{max-width:560px}
  .pc-tools{margin:-4px 0 10px}
  .pc-tools .btn-ghost{width:100%}
  .pc-pollform{margin-top:10px;padding:12px;background:var(--surface);border-radius:var(--r-md)}
  .pc-pollform .mgr-field{margin-bottom:8px}
  .pc-pollform select,.pc-pollform textarea{width:100%;font-size:var(--fs-input);border:1px solid var(--line);
    border-radius:var(--r-sm);padding:9px 11px;box-sizing:border-box}
  .pc-pollform textarea{min-height:60px;resize:vertical}
  .pc-lbl{display:block;font-size:var(--fs-sm);font-weight:700;color:var(--muted);margin:6px 0 4px}
  .pc-optrow{display:flex;gap:6px;align-items:center;margin-bottom:6px}
  .pc-optrow input{font-size:var(--fs-input);border:1px solid var(--line);border-radius:var(--r-sm);padding:8px 10px;min-width:0}
  .pc-optrow .pc-od{flex:1}
  .pc-oremove{border:none;background:none;color:var(--muted);font-size:var(--ic-md);cursor:pointer;flex:0 0 auto}
  #pc-addopt{margin:2px 0 10px}
  #pc-poll-send{width:100%}
  /* a poll rendered inside a message bubble */
  .pc-poll{margin-top:6px;display:flex;flex-direction:column;gap:6px}
  .pc-poll-h{font-size:var(--fs-sm);font-weight:800;color:var(--accent-dark)}
  .pc-opt{display:flex;align-items:center;gap:8px;text-align:left;width:100%;
    border:1px solid var(--line);background:var(--card);border-radius:var(--r-sm);padding:8px 10px;cursor:pointer}
  /* .9 была почти незаметной и ничего не сообщала: голос уже отдан, и об этом говорят
     .mine/.approved. Остался только курсор. */
  .pc-opt:disabled{cursor:default}
  .pc-opt.mine{border-color:var(--accent-deep);background:var(--accent-tint)}
  .pc-opt.approved{border-color:var(--ok-line);background:var(--ok-tint)}
  .pc-when{font-weight:700;font-size:var(--fs-sm);flex:0 0 auto}
  /* blox45 #17 — метка утверждённого варианта: точка вместо ✅. Цвет ей задаём тут, иначе она взяла
     бы цвет текста кнопки и «утверждено» перестало бы читаться с одного взгляда. */
  .pc-opt.approved .pc-when .ic{color:var(--ok-ink)}
  .pc-count{font-weight:800;color:var(--accent-dark);min-width:20px;text-align:center;flex:0 0 auto}
  .pc-voters{font-size:var(--fs-2xs);color:var(--muted);overflow-wrap:anywhere;flex:1}
  .pc-hint{font-size:var(--fs-2xs);color:var(--muted)}
  .pc-approved{font-size:var(--fs-xs);font-weight:700;color:var(--ok-ink)}
  /* PIN gate + methodologist «Доступы» */
  .pingate{max-width:360px}
  .pingate-in{width:100%;font-size:var(--fs-xl);letter-spacing:.3em;text-align:center;box-sizing:border-box;
    border:1px solid var(--line);border-radius:var(--r-md);padding:12px;margin:4px 0 8px}
  .pg-err{color:var(--alert-ink);font-size:var(--fs-sm);font-weight:600;margin-bottom:8px}
  .pingate .btn-pub{width:100%}
  .access-list{display:grid;grid-template-columns:1fr;gap:8px;margin-top:12px}
  @media(min-width:761px){ .access-list{grid-template-columns:1fr 1fr} }  /* группы в две колонки на ПК (blox34 #5) */
  .access-row{display:flex;align-items:center;justify-content:space-between;gap:12px;
    border:1px solid var(--line);border-radius:var(--r-md);padding:12px 14px;background:var(--card)}
  .access-row .ar-name{font-weight:700}
  .access-row .ar-par{font-size:var(--fs-sm);color:var(--muted)}
  .access-row .ar-pin{font-size:var(--fs-xl);font-weight:800;letter-spacing:.12em;color:var(--accent-dark)}
  /* blox42 #4: PIN + «Перевыпустить» едут вместе, не разрываясь при переносе строки (§3) */
  .access-row .ar-right{display:flex;align-items:center;gap:10px;flex-wrap:nowrap}


  /* ═══ ПЕРЕРИСОВКА B — плашки фактов на карточке сдачи (агент 2): форма бейджа B (скругление 6,
     без рамки), «на проверке» — цвет группы, как «Check N» на ростере (один смысл — один цвет). */
  .srind{border-radius:var(--r-badge);border-color:transparent}
  .srind.spend{background:var(--group);color:var(--on-group);border-color:transparent}
  .bdg{border-radius:var(--r-badge)}

  /* ═══ ПЕРЕРИСОВКА B — СЕГМЕНТНЫЙ ПЕРЕКЛЮЧАТЕЛЬ .onotes (агент 2, эскиз MonB «Notes | Tasks»).
     Два слова через слеш с подчёркиванием (blox53 #6) стали сегментами на серой дорожке:
     выбранный — белая плашка с чернилами, второй — серым текстом. Разметка та же (корень —
     <button class="onotes">, слова — .onw[data-m] с .on у текущего): клик по слову ведёт в его
     режим, мимо слов — переключает, как и было. Слеш остаётся в разметке, но не рисуется.
     Им же говорит «Список / Страница» окна учебника (.pgsw) — один вид на оба места. */
  .onotes{gap:0;padding:4px;min-height:44px;background:var(--btn-2-bg);border-radius:var(--r-sm);
    font-size:var(--fs-ctl)}
  .onotes .onsl{display:none}
  .onotes .onw,.onotes .onw.up,.onotes .onw.dn{display:flex;align-items:center;justify-content:center;
    height:36px;box-sizing:border-box;padding:0 12px;border-radius:var(--r-xs);transform:none;
    font-weight:600;color:var(--muted);
    transition:background-color var(--dur-state) var(--ease-standard),color var(--dur-state) var(--ease-standard)}
  .onotes .onw::before{inset:-4px 0}
  .onotes .onw.on{background:var(--seg-on);color:var(--ink)}
  .onotes .onw.on::after{display:none}
  /* на телефоне тумблер в шапке листа занимает свою строку во всю ширину — сегменты делят её поровну */
  @media(max-width:760px){ .opane-h .onotes .onw{flex:1 1 0} }
