
/* layout.css — каркас приложения и адаптив. Метрики из дизайна архива. */

#app{position:fixed;inset:0;display:flex;background:var(--bg);color:var(--text);overflow:hidden}

/* ---- Рейл папок (десктоп) ---- */
#rail{width:70px;flex-shrink:0;display:flex;flex-direction:column;align-items:center;padding:8px 0;background:var(--rail-bg);border-right:1px solid rgba(0,0,0,.25);z-index:6;overflow-y:auto}
.rail-btn{position:relative;overflow:hidden;width:48px;height:44px;border:none;border-radius:12px;background:transparent;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--rail-fg);margin-bottom:6px;flex-shrink:0}
.rail-btn:hover{background:var(--rail-active)}
/* Гамбургер горит, пока открыта шторка: круг должен во что-то приезжать, иначе он расходится и
   исчезает в никуда. Для кнопки-действия «активно» и значит «меню сейчас открыто». */
.rail-btn.on,.rail-btn.on:hover{background:var(--rail-press);color:#fff}
.rail-folder{position:relative;overflow:hidden;width:62px;padding:9px 2px 6px;margin-bottom:2px;border:none;border-radius:14px;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:5px;color:var(--rail-fg);background:transparent;flex-shrink:0}
.rail-folder:hover{background:var(--rail-active)}
/* Выбранная папка держит своё состояние и под курсором: :hover тут не «сверху», а «вместо»,
   поэтому у .active своя пара селекторов с большей специфичностью. */
.rail-folder.active,.rail-folder.active:hover{color:var(--accent);background:var(--rail-press)}

/* ---- Круг из точки нажатия ---- */
/* Обрезка кругу — не его дело: он всегда квадрат-круг любого размера, а границу задаёт кнопка
   своим overflow:hidden и своим же радиусом. Поэтому на рейле не нужно повторять скругления, и
   круг не вылезет за угол, каким бы этот угол ни стал.
   Цвет — тот самый --rail-press: круг не «эффект поверх», а сам новый фон, который доезжает до
   краёв. Доехал — кнопка уже в нужном состоянии, и снимать его не с чего; у кнопки без состояния
   круг гасится в конце, поэтому одна анимация годится обоим.
   Дети кнопки поднимаются над кругом: иначе значок и подпись он закрасит собой. */
.rail-btn>*,.rail-folder>*{position:relative;z-index:1}
.ripple{position:absolute;z-index:0;border-radius:50%;background:var(--rail-press);pointer-events:none;transform:scale(0);animation:rippleOut .5s cubic-bezier(.22,1,.36,1) forwards}
@keyframes rippleOut{0%{transform:scale(0);opacity:1}55%{transform:scale(1);opacity:1}100%{transform:scale(1);opacity:0}}
.rf-ic{display:flex;align-items:center;justify-content:center}
.rf-lb{font-size:11px;font-weight:600;letter-spacing:-.1px;max-width:60px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rf-badge{position:absolute;top:4px;right:8px;min-width:18px;height:18px;border-radius:9px;background:var(--accent);color:#fff;font-size:10.5px;font-weight:700;display:flex;align-items:center;justify-content:center;padding:0 5px;border:2px solid var(--rail-bg)}
.rail-spacer{flex:1;min-height:8px}

/* ---- Сайдбар ---- */
#sidebar{width:340px;min-width:0;flex-shrink:0;display:flex;flex-direction:column;background:var(--panel);backdrop-filter:blur(var(--blur)) saturate(1.4);-webkit-backdrop-filter:blur(var(--blur)) saturate(1.4);border-right:1px solid var(--border);z-index:5}
/* Поиск и «+» — одна высота на двоих, одним значением. Раньше у кнопки высота была задана явно
   (38px), а у поля вычислялась из содержимого: 14px текста + по 9px отступов ≈ 35px. Кнопка
   выпирала сверху и снизу на пару пикселей. Через общую переменную они не разъедутся снова:
   .new-btn лежит внутри .side-search и наследует её. */
.side-search{--sidetop-h:38px;padding:12px 14px 8px;display:flex;align-items:center;gap:10px}
.side-search .wrap{flex:1;display:flex;align-items:center;gap:8px;background:var(--hover);border:none;border-radius:18px;padding:0 14px;height:var(--sidetop-h)}
.side-search input{border:none;background:transparent;outline:none;font-size:14px;width:100%}
.new-btn{width:var(--sidetop-h);height:var(--sidetop-h);border:none;border-radius:50%;background:var(--hover);color:var(--text);cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:22px;line-height:1}
.new-btn:hover{background:var(--accent-soft);color:var(--accent)}
#directory-panel{border-bottom:1px solid var(--border);max-height:42%;overflow-y:auto}
.panel-label{font-size:10.5px;color:var(--text2);padding:10px 16px 4px;text-transform:uppercase;letter-spacing:.06em}
#conv-list{flex:1;overflow-y:auto;padding:6px}
#mobnav{display:none}

/* ---- Окно чата ---- */
#chatpane{flex:1;min-width:0;display:flex;flex-direction:column;background-image:var(--wp-image,none),var(--wallpaper);background-repeat:var(--wp-repeat,repeat),no-repeat;background-size:var(--wp-size,64px),cover;background-position:center,center;position:relative}
#chathead{display:flex;align-items:center;gap:10px;padding:8px 14px;background:var(--panel);backdrop-filter:blur(var(--blur)) saturate(1.4);-webkit-backdrop-filter:blur(var(--blur)) saturate(1.4);border-bottom:1px solid var(--border);z-index:4}
.back-btn{display:none;width:36px;height:36px;border:none;background:transparent;border-radius:11px;cursor:pointer;color:var(--accent);align-items:center;justify-content:center;flex-shrink:0}
.back-btn svg{width:24px;height:24px}
.peer-head{display:flex;align-items:center;gap:10px;cursor:pointer;flex:1;min-width:0}
/* flex:1 — чтобы имя занимало свободное место, а лупа поиска (задумка #75) прижималась к
   правому краю блока имени. min-width:0 держит многоточие у длинных имён. */
.head-text{min-width:0;flex:1}
/* Имя собеседника крупнее на 30% (задумка #76): 15px → 19.5px. */
#peer-name{font-weight:700;font-size:19.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#peer-status{font-size:12.5px;color:var(--text2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#peer-status.online{color:var(--accent);font-weight:600}

/* ---- Диалог не выбран ---- */
/* Шапка, лента и ввод существуют всегда, но до открытия диалога им нечего показывать: пустое имя,
   пустой статус и поле, из которого сообщение уйдёт в никуда. Прячем их разом по body.inchat —
   классом, который showScreen() уже ведёт (он же переключает экраны на мобильном), и ставим на их
   место заглушку. На узком экране правило не мешает: там #chatpane целиком display:none. */
body:not(.inchat) #chathead,
body:not(.inchat) #messages,
body:not(.inchat) #composer-banner,
body:not(.inchat) #composer{display:none}
#chat-empty{display:none;flex:1;align-items:center;justify-content:center;padding:24px}
body:not(.inchat) #chat-empty{display:flex}
.ce-chip{padding:10px 18px;border-radius:18px;background:var(--panel);backdrop-filter:blur(var(--blur)) saturate(1.4);-webkit-backdrop-filter:blur(var(--blur)) saturate(1.4);border:1px solid var(--border);box-shadow:0 8px 24px rgba(0,0,0,.06);color:var(--text2);font-size:13.5px;text-align:center;line-height:1.45;max-width:320px}

/* Плавный скролл ленты (без пустот и рывков). Три поправки, все — про растеризацию, не про данные:
   1) transform:translateZ(0) — скроллеру свой слой: растр готовится с запасом заранее, а не в
      момент инерционного свайпа, когда браузер не успевает и показывает пустые тайлы;
   2) overflow-anchor:none — якорение браузера выключено: подшивка старых страниц САМА держит
      scrollTop (js/render.js → onHistory), и когда позицию правят двое — браузер и код — лента
      дёргается;
   3) #messages * держит обычный round у МЕЛОЧИ ленты: superellipse(2.6) со звёздочки в tokens.css
      попадал бы на каждый скруглённый элемент (кадры, плашки, кольца, точки — десятки на экран) и
      считается заметно дороже round при каждой отрисовке; на инерционном скролле это рывки. Но два
      ГЛАВНЫХ силуэта переписки — пузырь и аватарка — фирменную форму C-MSG несут (правило ниже,
      беклог #113/#114/#115): их на ряд один-два, не десятки, цена ничтожна. Вне ленты сглаженные
      углы остаются как были.
   Четвёртая поправка живёт в components.css: входная анимация .mrow больше не играет хором на
   страницах истории. */
#messages{flex:1;overflow-y:auto;overflow-x:hidden;padding:16px 14px 8px;display:flex;flex-direction:column;gap:5px;overflow-anchor:none;transform:translateZ(0)}
#messages *{corner-shape:round}
/* Беклог #113/#114/#115: фирменная форма — и в ленте, но только у её главных силуэтов.
   Специфичность (#messages .класс) перебивает #messages * — round остаётся у всего остального.
   Аватарка так совпадает с шапкой/списком, где суперэллипс со звёздочки в tokens.css и был. */
#messages .msgbubble,
#messages .deskavatar{corner-shape:superellipse(2.6)}
#older-hint{text-align:center;font-size:11px;color:var(--text2);padding:2px 0;min-height:16px}

#composer{display:flex;align-items:flex-end;gap:8px;padding:10px 12px calc(10px + env(safe-area-inset-bottom));background:var(--panel);backdrop-filter:blur(var(--blur)) saturate(1.4);-webkit-backdrop-filter:blur(var(--blur)) saturate(1.4);border-top:1px solid var(--border);z-index:4}
.composer-pill{flex:1;display:flex;align-items:flex-end;gap:2px;background:var(--panel2);border:1px solid var(--border);border-radius:calc(var(--bub-radius,14px) + 8px);padding:3px 4px}
.pill-btn{width:38px;height:38px;flex-shrink:0;border:none;background:transparent;border-radius:50%;cursor:pointer;color:var(--text2);display:flex;align-items:center;justify-content:center}
.pill-btn:hover{background:var(--hover)}
/* Поле ввода — <textarea> с одной строкой на старте (задумки #165/#164/#159). Правило почти не
   изменилось: resize:none и max-height тут лежали и раньше, как раз под многострочное поле, а
   font-family/color textarea наследует общим правилом из tokens.css.
   max-height и есть «4-5 строк максимум»: 5 × 20.3px (14.5 × 1.4) + 18px паддингов ≈ 120px; выше
   начинается своя прокрутка поля — её включает autoGrowInput, пока не упёрлись, полосы нет.
   min-height — страховка на строку: на телефоне #chatpane до body.inchat лежит с display:none, а у
   скрытого элемента scrollHeight равен нулю (та же ловушка, что у прокрутки в onOpened), и
   посчитанная в этот момент высота была бы нулевой. */
#msg-input{flex:1;resize:none;border:none;background:transparent;padding:9px 4px;font-size:14.5px;outline:none;min-height:38px;max-height:120px;overflow-y:hidden;line-height:1.4}
#send-btn{width:44px;height:44px;flex-shrink:0;border:none;border-radius:12px;background:transparent;color:var(--accent);cursor:pointer;display:flex;align-items:center;justify-content:center}
#send-btn:hover{background:var(--hover)}
#send-btn svg{margin-left:1px}

/* ---- Мобильная адаптация (как в дизайне) ---- */
.set-tabbar{display:none}

@media(max-width:760px){
  #rail{display:none}
  #sidebar{width:100%;max-width:none;border-right:none}
  #chatpane{display:none}
  body.inchat #sidebar{display:none}
  body.inchat #chatpane{display:flex}
  .back-btn{display:flex}
  #profile-panel{width:100%}
  .deskavatar{display:none}
  .mrow.mmine{align-items:flex-end}

  /* нижняя навигация */
  #mobnav{display:flex;padding:8px 12px calc(10px + env(safe-area-inset-bottom));gap:6px}
  .mobnav-bar{flex:1;display:flex;justify-content:space-around;align-items:center;background:var(--panel2);border:1px solid var(--border);border-radius:22px;box-shadow:0 6px 16px rgba(0,0,0,.08);padding:6px 4px}
  .mobnav-item{position:relative;display:flex;flex-direction:column;align-items:center;gap:2px;padding:6px 16px;color:var(--text2);cursor:pointer;font-size:11px;font-weight:600}
  .mobnav-item.active{color:var(--accent)}
  /* Счётчик непрочитанного у папки — как rf-badge на рейле, только компактнее: пункт мельче.
     Обводка цветом самой полосы, чтобы кружок читался поверх иконки, а не сливался с ней. */
  .mobnav-badge{position:absolute;top:1px;right:8px;min-width:17px;height:17px;border-radius:9px;background:var(--accent);color:#fff;font-size:10px;font-weight:700;display:flex;align-items:center;justify-content:center;padding:0 4px;border:2px solid var(--panel2)}

  /* #69: настройки на телефоне — полноэкранный лист с нижним таб-баром (как основной экран).
     Селектор через #settings-modal — заведомо перебивает базовое .modal-sheet.set-sheet. */
  #settings-modal{padding:0}
  #settings-modal .set-sheet{width:100vw;max-width:none;height:100vh;height:100dvh;max-height:none;border-radius:0}
  #settings-modal .set-tabbar{display:block;flex-shrink:0;border-top:1px solid var(--border);padding:8px 12px calc(10px + env(safe-area-inset-bottom))}

  /* плавающие «облачка» шапки и ввода */
  #chathead{position:absolute;top:0;left:0;right:0;z-index:8;background:transparent;border-bottom:none;padding:9px 9px;gap:7px}
  /* Нижний запас — под плавающий композер: сообщения уезжают ПОД него и просвечивают размытыми,
     как под шапкой; запас не даёт последнему сообщению навсегда спрятаться за стеклом. */
  #messages{padding:78px 14px calc(74px + env(safe-area-inset-bottom))}
  .headseg{border-radius:24px;background:var(--panel);backdrop-filter:blur(20px) saturate(1.6);-webkit-backdrop-filter:blur(20px) saturate(1.6);border:1px solid var(--border);box-shadow:0 8px 24px rgba(0,0,0,.08);height:54px;display:flex;align-items:center}
  .peer-head{padding:6px 14px 6px 6px}
  .back-btn{width:54px;height:54px;border-radius:50%;flex:0 0 auto;border:1px solid var(--border)}
  .back-btn svg{width:26px;height:26px}
  #closeness-badge{background:var(--panel);backdrop-filter:blur(20px) saturate(1.6);-webkit-backdrop-filter:blur(20px) saturate(1.6);border-radius:24px;height:54px;padding:0 16px;box-shadow:0 8px 24px rgba(0,0,0,.08)}
  /* Низ — то же стекло, что и верх (задумка владельца): композер снят с потока и лежит ПОВЕРХ
     ленты, сообщения при скролле уезжают под него, а пилюля и кнопки — чуть прозрачные, с тем же
     блюром, что сегменты шапки. Сами панельки красит общее правило стекла в components.css. */
  #composer{position:absolute;left:0;right:0;bottom:0;z-index:8;background:transparent;border-top:none;padding:8px 9px calc(9px + env(safe-area-inset-bottom));gap:8px}
  .composer-pill{background:var(--panel);backdrop-filter:blur(20px) saturate(1.6);-webkit-backdrop-filter:blur(20px) saturate(1.6);box-shadow:0 8px 24px rgba(0,0,0,.08);border-radius:calc(var(--bub-radius,14px) + 10px)}
  /* Кнопки отправки и записи — стеклянные кружки с акцентной иконкой, как «назад» в шапке.
     Фон, блюр и тень им даёт общее правило стекла (components.css); здесь — только цвет иконки
     записи (у отправки акцент уже в базовом правиле). Селектор нарочно тяжёлый: базовый
     #rec-btn{color:var(--text2)} лежит в components.css и в каскаде победил бы, а :not(.recording)
     отдаёт идущую запись её собственному правилу (белая иконка на акцентном круге). */
  body:not(.recording) #composer #rec-btn{color:var(--accent)}
  /* Плашка ответа и подсказка команд жили над вводом в потоке — с плавающим композером они
     всплывают над ним теми же стеклянными карточками. Высоты у них разные и заранее не известны,
     поэтому якорь один: верх композера (63px = 8 + пилюля 46 + 9). */
  /* Композер растёт (многострочное поле), поэтому число 63px здесь врало бы на второй же строке:
     плашка ответа и подсказка команд наехали бы на поле. Едем от живой высоты композера — её
     публикует autoGrowInput; запасное значение = прежнее число, включая безопасную зону. */
  #composer-banner,#cmd-hints{position:absolute;left:9px;right:9px;bottom:var(--composer-h, calc(63px + env(safe-area-inset-bottom)));z-index:8;border:1px solid var(--border);border-radius:16px;background:var(--panel);-webkit-backdrop-filter:blur(20px) saturate(1.6);backdrop-filter:blur(20px) saturate(1.6);box-shadow:0 8px 24px rgba(0,0,0,.08)}
  /* #68: плашка ответа сидит на поле ввода единым блоком — скругляем только верх, тень мягче. */
  #composer-banner{border-radius:16px 16px 0 0;box-shadow:0 -1px 8px rgba(0,0,0,.05)}
  #emoji-panel{right:9px;bottom:78px}
}


/* ---- Свайпы между разделами: переезд вкладок (задумка #141) ---- */
/* Едут только списки - рама (поиск сверху, навигация снизу) стоит на месте. Перечисление в
   :is() и есть содержимое вкладки: всё, что pickFolder показывает и прячет внутри #sidebar.
   Обёртки под них заводить не стал - это перекроила бы разметку ради одной анимации.
   overflow-x:clip у #sidebar - чтобы уехавшая вкладка не рождала горизонтальную прокрутку;
   overflow-y остаётся прежним (clip + visible уживаются, в отличие от hidden + visible).
   Уход - forwards: вкладка обязана ДОЖДАТЬСЯ подмены содержимого за краем экрана, а не
   прыгнуть обратно на последнем кадре.
   Замедление у въезда мягче, чем у ухода: так переезд читается как «встало на место», а не
   как «проскочило». Уважение к prefers-reduced-motion берётся даром - в tokens.css анимации
   глобально схлопываются до 0.01ms. */
#sidebar{overflow-x:clip}
#sidebar.sect-out-left > :is(#directory-panel,#conv-list,#channel-list,#channel-empty,#list-empty,#folder-empty,#global-msgs){animation:sectOutLeft .15s ease-in forwards}
#sidebar.sect-out-right > :is(#directory-panel,#conv-list,#channel-list,#channel-empty,#list-empty,#folder-empty,#global-msgs){animation:sectOutRight .15s ease-in forwards}
#sidebar.sect-in-right > :is(#directory-panel,#conv-list,#channel-list,#channel-empty,#list-empty,#folder-empty,#global-msgs){animation:sectInRight .2s cubic-bezier(.22,1,.36,1)}
#sidebar.sect-in-left > :is(#directory-panel,#conv-list,#channel-list,#channel-empty,#list-empty,#folder-empty,#global-msgs){animation:sectInLeft .2s cubic-bezier(.22,1,.36,1)}
@keyframes sectOutLeft{to{transform:translateX(-100%)}}
@keyframes sectOutRight{to{transform:translateX(100%)}}
@keyframes sectInRight{from{transform:translateX(100%)}to{transform:none}}
@keyframes sectInLeft{from{transform:translateX(-100%)}to{transform:none}}

/* Настройки - четвёртая вкладка ленты, но живут модалкой, поэтому едет её лист. На телефоне
   он полноэкранный (#69) и переезд выглядит так же, как у списков; на десктопе это просто
   мягкое появление сбоку, вреда от него нет. */
#settings-modal.sect-in .set-sheet{animation:sectInRight .22s cubic-bezier(.22,1,.36,1)}
#settings-modal.sect-out .set-sheet{animation:sectOutRight .15s ease-in forwards}
