  /* ── сайдбар: «мои чаты» ──
     Панель не залита и не отбита рамкой: в дизайн-системе фон один на весь
     кабинет, а панель от ленты отделяет складка бумаги — фотография, а не
     `border-left`. Складка висит на .app (см. ниже), потому что сама панель
     схлопывается в ноль и утащила бы складку с собой. */
  /* Левое поле 32px — как в макете, и не только ради ритма: пятно под круглой
     кнопкой вылетает влево на 39px, а панель режет всё лишнее (overflow:hidden
     нужен для сворачивания). На прежних 22px от края пятно срезалось пополам и
     читалось приклеенным к краю экрана, а не подсветкой под пальцем. */
  .sidebar { width:266px; flex:0 0 266px; background:transparent; border-right:0;
             display:flex; flex-direction:column; padding:0 10px 12px 32px;
             position:relative; z-index:1 }
  /* Складка. Картинка горизонтальная, поэтому элемент лежит «лёжа» и
     разворачивается трансформом, а растягивается 100% 100% — при cover от
     складки остаётся кусок посередине. */
  .app::before { content:''; position:absolute; z-index:0; pointer-events:none;
                 top:50%; left:270px; width:100vh; height:var(--fold-w);
                 transform:translate(-50%,-50%) rotate(90deg);
                 background:var(--fold-src) center / 100% 100% no-repeat;
                 opacity:var(--fold-opacity);
                 transition:opacity var(--dur-panel) var(--ease-out), left var(--dur-panel) var(--ease-out) }
  /* Панель свернули — складке нечего разделять. */
  .app.narrow::before { opacity:0; left:0 }
  /* ── свернуть/развернуть сайдбар ──
     Сворачиваем по ширине, а не display:none: панель остаётся в потоке, и переход
     получается плавным. Содержимое режем overflow:hidden — иначе кнопки и названия
     чатов вылезают за схлопнутый край. */
  /* Длительность и кривая те же, что у складки (.app::before) — иначе после
     входа панель и линия выезжают вразнобой, и видно, что это два разных
     элемента, а не один разворачивающийся край страницы. */
  .sidebar { transition:width var(--dur-panel) var(--ease-out),
                        flex-basis var(--dur-panel) var(--ease-out),
                        padding var(--dur-panel) var(--ease-out); overflow:hidden }
  .app.narrow .sidebar { width:0; flex-basis:0; padding-left:0; padding-right:0; border-right:0 }
  /* «Новый чат» — знак, а не таблетка с надписью: в макете это просто «+».
     Плашки нет, под курсором проявляется то же мягкое гало, что у круглых
     кнопок в композере. Стоит по левому краю списка, над ним. */
  /* Отбивка от знака в углу — 26px, как в макете: «+» там начинается на 80px
     от верха экрана, а знак кончается на 54-м. Впритык они читались одной
     группой, хотя это разные вещи: знак — выход на первый экран, «+» — новый
     разговор. */
  .newbtn { position:relative; display:grid; place-items:center; width:24px; height:24px;
            margin:80px 0 0; padding:0; border:0; border-radius:var(--radius-mark);
            background:none; cursor:pointer; color:rgb(0 0 0 / .8) }
  .newbtn svg { width:24px; height:24px; position:relative; z-index:1 }
  /* В оригинале сам знак тоже анимируется: линия растёт с 1.2 до 1.7 по
     пружине .55s / bounce .18. Простое затемнение знака этого жеста не даёт. */
  .newbtn svg path { stroke-width:1.2;
                     transition:stroke-width var(--dur-action-hover) var(--spring-action-hover) }
  /* Обрезка в эллипс обязательна. В покое невидимое пятно имеет размер
     95×66, hover-вариант — 81×66; оба состояния центрированы под знаком. */
  .newbtn::before { content:''; position:absolute; inset:var(--blob-inset);
                    border-radius:var(--radius-mark); overflow:hidden;
                    background:var(--blob-src) center / cover no-repeat; opacity:0;
                    pointer-events:none;
                    transition:opacity var(--dur-action-hover) var(--spring-action-hover),
                               inset var(--dur-action-hover) var(--spring-action-hover) }
  .newbtn:hover::before, .newbtn:focus-visible::before {
    inset:var(--blob-plus-hover-inset); opacity:1;
  }
  .newbtn:hover svg path, .newbtn:focus-visible svg path { stroke-width:1.7 }
  .convos { flex:1; overflow-y:auto; margin-top:8px; display:flex; flex-direction:column; gap:2px }
  /* Пункт списка: ни плашки, ни подложки — на бумаге они читаются наклейкой.
     Открытый чат отличается непрозрачностью и более жирной осью. */
  .convo { display:flex; align-items:center; gap:8px; padding:9px 10px 9px 0; border-radius:var(--radius-hit);
           cursor:pointer; font-size:13.5px; color:var(--ink);
           font-variation-settings:var(--axis-item); opacity:.6;
           transition:opacity var(--dur-hover) var(--ease-out) }
  .convo:hover { opacity:.85 }
  .convo.active { opacity:1; font-variation-settings:var(--axis-active) }
  /* min-width:0 обязателен: без него flex-элемент не даёт себя сжать, и вместо
     многоточия в названии распирало бы всю строку меткой состояния */
  .convo .t { flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
  /* Диалог кампании — в две строки: колонка узкая (266px), и в одну строку рядом с
     меткой состояния помещался 21 символ. Отличительная часть названия («…Ренессанс»,
     «…у метро Василеостровская») стоит в конце и не показывалась НИКОГДА — все чаты
     выглядели одинаково. Две строки дают ~55 символов, метка уезжает под название и
     больше не отъедает ширину. Полное название — в тултипе. */
  .convo.multi { align-items:flex-start; padding:8px 10px 8px 0 }
  .convo .col { flex:1; min-width:0; display:flex; flex-direction:column; align-items:flex-start; gap:4px }
  /* Метрики шрифта поднимают видимую массу букв относительно круглого знака,
     хотя контейнеры стоят на одной линии. Небольшая оптическая коррекция вниз. */
  .convo.multi .col { transform:translateY(2px) }
  .convo.multi .t { align-self:stretch; white-space:normal; display:-webkit-box; -webkit-line-clamp:2;
                    -webkit-box-orient:vertical; overflow:hidden; line-height:1.34; overflow-wrap:anywhere }
  /* Метка состояния — надпись, а не кнопка: нажать её нельзя, значит и глубины
     у неё быть не должно (та же ошибка, что была у реплики человека). Остаётся
     бледная подложка — её хватает, чтобы метка читалась ярлыком. Цветом не
     различаем: на ней написано словом, что происходит. */
  .convo .st { flex:0 0 auto; font-size:8.5px; letter-spacing:.05em; text-transform:uppercase;
               font-variation-settings:var(--axis-active);
               white-space:nowrap; padding:3px 8px 4px; border-radius:var(--radius-mark);
               background:var(--ink-faint); border:0; color:var(--ink-muted);
               box-shadow:none }
  .convo .st.ok { color:var(--ink-strong) }
  .convo .st.wait { color:var(--ink-muted) }
  /* Отказ — единственное состояние, которому положен цвет: тот самый красный
     из знака, других в системе нет. */
  .convo .st.bad { color:var(--bad) }
  .convo input.rename { flex:1; min-width:0; font:inherit; font-size:13.5px; padding:4px 10px;
                        border:0; border-radius:var(--radius-mark); outline:none;
                        background:var(--paper); box-shadow:var(--shadow-chip) }
  /* поле переименования встаёт на место названия ВНУТРИ колонки, а у неё
     align-items:flex-start — без stretch оно сжалось бы до ширины текста */
  .convo .col input.rename { align-self:stretch; width:100% }
  .convo .del { opacity:0; border:none; background:none; cursor:pointer; color:var(--ink-muted);
                font-size:16px; line-height:1; padding:0 2px }
  .convo:hover .del { opacity:.55 }
  .convo .del:hover { opacity:1; color:var(--ink) }
  /* Закреплённые разделы отбиты не линией, а воздухом: рамок система не знает. */
  .pinned { border-top:0; padding-top:14px; margin-top:10px }
  .pinned .convo { opacity:.75 }
  .pinned .convo:hover, .pinned .convo.active { opacity:1 }
  /* Знак открытого пункта — единственное цветное пятно на экране: четыре
     сектора в круге. Цвет значит ровно «вы здесь», поэтому знак виден только
     у открытого пункта: у обычных чатов его и не создают, у двух закреплённых
     он стоит в разметке всегда и показывается этим правилом. */
  .convo .spark { display:none }
  .convo.active .spark { display:block;
                  width:24px; height:24px; flex:0 0 24px; border-radius:var(--radius-mark);
                  overflow:hidden; font-size:0; line-height:0;
                  animation:pp-mark-in var(--dur-mark) var(--spring-bounce) both }
  .convo.active .spark svg { display:block; width:100%; height:100% }
  @keyframes pp-mark-in { from { transform:scale(.4); opacity:0 } to { transform:none; opacity:1 } }
  .pin-n { margin-left:auto; font-size:11px; color:var(--ink-muted); font-variant-numeric:tabular-nums }
  .foot { padding:8px; font-size:12px; color:var(--ink-muted) }
  .foot a { color:var(--ink-muted); text-decoration:none }
  .foot a:hover { color:var(--ink) }
  /* Профиль в правом верхнем углу — там же, где у гостя знак человека.
     Имя и компанию в углу не показываем: они есть в меню, а в углу нужен знак.
     Координаты те же, что у .hd-acc, — это один и тот же угол. */
  .profile-foot { position:absolute; z-index:12; right:24px; top:16px; margin:0; padding:0; border-top:0 }
  .app.guest .profile-foot { display:none }
  .profile-link { display:block; padding:0; border-radius:var(--radius-mark);
                  color:var(--ink-strong); text-decoration:none }
  .profile-link:hover { opacity:1 }
  /* Знак человека — чёрный круг с инициалами, ростом с соседний знак у гостя. */
  .profile-avatar { width:32px; height:32px; flex:0 0 32px; border-radius:var(--radius-mark); display:grid;
                    place-items:center; background:var(--ink); color:var(--paper); cursor:pointer;
                    font-size:11px; font-variation-settings:var(--axis-active);
                    transition:transform var(--dur-logo) var(--spring) }
  .profile-avatar:hover { transform:scale(1.12) }
  /* Меню висит над бумагой — единственный случай, когда тень наружу. */
  .profile-pop { display:none; position:absolute; z-index:55; right:0; top:44px; width:190px;
                 padding:6px; background:var(--paper); border:0; border-radius:var(--radius-card);
                 box-shadow:var(--shadow-pop) }
  .profile-pop.on { display:block }
  .profile-pop a { display:block; padding:9px 11px; border-radius:8px; color:var(--ink-strong);
                   text-decoration:none; font-size:12.5px }
  .profile-pop a:hover { background:var(--ink-faint); color:var(--ink) }

  /* ── пока кампаний нет, панель свёрнута ──
     Разворачивать пустую колонку нечем и незачем — на первом экране слева
     всё равно ничего нет. Кнопку «показать панель» тоже не рисуем: показывать
     нечего. Класс .blank ставит renderConvos, и снимает его сама же — как
     только у гостя появляется первый чат, панель возвращается.

     Складка при этом остаётся: она часть бумаги, а не граница колонки, и
     просто уезжает к левому краю. */
  .app.blank .sidebar { width:0; flex-basis:0; padding-left:0; padding-right:0 }
  .app.blank::before { left:var(--fold-x-blank) }
