:root[data-theme="dark"]{
  --bg:#1a1a2e; --bg2:#16213e; --bg3:#0f3460; --border:#0f3460;
  --accent:#e94560; --accent2:#90caf9; --text:#e0e0e0; --text-muted:#aaa; --text-dim:#666;
  --input-bg:#0f3460; --input-bg-warn:#3d3418; --input-brd:#1a4d8a; --hover:#0f3460; --card-bg:#16213e; --weekend-bg:#3a1a24;
  --ok:#4caf50; --warn:#ffb300; --err:#f44336; --color-scheme:dark;
  --btn-primary-text:#0a1628;
  --card-shadow:0 0 0 1px rgba(0,0,0,.4), 0 4px 10px rgba(0,0,0,.5), 0 1px 3px rgba(0,0,0,.4);
}
:root[data-theme="light"]{
  --bg:#f0f2f5; --bg2:#ffffff; --bg3:#e3eaf5; --border:#c8d3e6;
  --accent:#c62a47; --accent2:#1565c0; --text:#1a1a2e; --text-muted:#555; --text-dim:#999;
  --input-bg:#f8f9fc; --input-bg-warn:#fdf6d8; --input-brd:#b0bdd6; --hover:#e3eaf5; --card-bg:#ffffff; --weekend-bg:#fbe4e4;
  --ok:#2e7d32; --warn:#e65100; --err:#c62828; --color-scheme:light;
  --btn-primary-text:#fff;
  --card-shadow:0 0 0 1px rgba(20,30,50,.10), 0 4px 10px rgba(20,30,50,.18), 0 1px 3px rgba(20,30,50,.12);
}
/* [data-mode="webview"] и .webview-mode — два способа определения webview-режима
   (сервер и JS соответственно); оба переопределяют :root[data-theme] без
   !important за счёт более высокой специфичности селектора. */
html[data-mode="webview"][data-theme="dark"],
html.webview-mode[data-theme="dark"]{
  --bg:#1E100D; --bg2:#271815; --bg3:#2C1C19; --border:#5B403C;
  --accent:#8A0002; --accent2:#FFB4A9; --text:#F9DCD7; --text-muted:#E4BEB8; --text-dim:#AB8984;
  --input-bg:#271815; --input-bg-warn:#3d3418; --input-brd:#AB8984; --hover:#372623; --card-bg:#2C1C19; --weekend-bg:#79251B;
  --ok:#4caf50; --warn:#ffb300; --err:#FFB4AB; --color-scheme:dark;
  --btn-primary-text:#FFCDC5;
  --card-shadow:0 0 0 1px rgba(0,0,0,.45), 0 4px 10px rgba(0,0,0,.55), 0 1px 3px rgba(0,0,0,.45);
  /* inverseSurfaceDark — значение из monitorbms4 (Color.kt), не придуманное */
  --inverse-surface:#F9DCD7;
}
html[data-mode="webview"][data-theme="light"],
html.webview-mode[data-theme="light"]{
  --bg:#FFFFFF; --bg2:#FFFFFF; --bg3:#FFDAD5; --border:#E4BEB8;
  --accent:#B11910; --accent2:#9F4034; --text:#271815; --text-muted:#5B403C; --text-dim:#8F706B;
  --input-bg:#FFFFFF; --input-bg-warn:#fdf6d8; --input-brd:#8F706B; --hover:#FFDAD5; --card-bg:#FFFFFF; --weekend-bg:#D0CECE;
  --ok:#2e7d32; --warn:#e65100; --err:#BA1A1A; --color-scheme:light;
  --btn-primary-text:#FFFFFF;
  --card-shadow:0 0 0 1px rgba(60,20,15,.12), 0 4px 10px rgba(60,20,15,.20), 0 1px 3px rgba(60,20,15,.14);
  /* inverseSurfaceLight — значение из monitorbms4 (Color.kt), не придуманное */
  --inverse-surface:#3E2C29;
}
*{box-sizing:border-box;margin:0;padding:0}
body{font:14px/1.5 'Segoe UI',Arial,sans-serif;background:var(--bg);color:var(--text);min-height:100vh;color-scheme:var(--color-scheme)}
button{cursor:pointer;font:inherit;border:none;border-radius:6px;padding:8px 14px;background:var(--bg3);color:var(--text)}
button.primary,button.danger{color:#fff}
button.primary{background:var(--accent2);color:var(--btn-primary-text)}
button.danger{background:var(--err)}
button.secondary{background:var(--bg3);color:var(--text)}
button.small{padding:4px 10px;font-size:12px}
button.icon-btn{background:none;font-size:18px;padding:4px 8px}
button:hover{filter:brightness(1.1)}
/* нигде в приложении не было визуального отличия disabled-кнопки от обычной
   (только атрибут, реально блокирующий клик) — выглядело так, будто кнопку
   вообще не заблокировали (реальная жалоба — «Особое мнение»/«Дорожная
   карта» до формирования итогов казались нажимаемыми). */
button:disabled{opacity:.45;cursor:not-allowed;filter:none}
input,select,textarea{font:inherit;background:var(--input-bg);color:var(--text);border:1px solid var(--input-brd);border-radius:6px;padding:7px 10px}
h1{font-size:18px;color:var(--accent)}
h2{font-size:16px;margin-bottom:12px}
h3{font-size:13px;color:var(--accent2);margin-bottom:8px;text-transform:uppercase;letter-spacing:.5px}
.dim{color:var(--text-dim)}
.spacer{flex:1}

/* login */
.login-wrap{display:flex;align-items:center;justify-content:center;min-height:100vh}
.login-card{background:var(--card-bg);box-shadow:var(--card-shadow);border-radius:12px;padding:32px;width:340px;display:flex;flex-direction:column;gap:12px}
.login-card h1{text-align:center;margin-bottom:8px}
.login-btns{display:flex;gap:8px}
.login-btns button{flex:1}
.modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:1500}
.modal-check{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--text-muted)}
.err-msg{color:var(--err);font-size:13px;min-height:18px;text-align:center}
/* #webview-loader показывается вместо формы логина, когда сервер уже
   авторизовал по POST (см. app/main.py:index_post) */
.loader-spinner{width:36px;height:36px;border-radius:50%;border:4px solid var(--border);border-top-color:var(--accent);animation:spin 0.8s linear infinite}

/* «Фраза ИИ» — текст обычно на пару предложений, узкой карточки логина не
   хватает, чтобы видеть его целиком без прокрутки */
.ai-phrase-card{width:560px;max-width:92vw}
.ai-phrase-card textarea{width:100%;min-height:220px;resize:vertical}

/* admin */
.admin-modal-card{width:960px;max-width:95vw;max-height:86vh;overflow-y:auto}
.admin-toolbar{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-bottom:10px}
.admin-toolbar #admin-user-search{flex:1;min-width:180px}
.admin-hide-blocked{display:flex;align-items:center;gap:6px;font-size:13px;cursor:pointer;white-space:nowrap}
.upload-audio-modes{display:flex;flex-direction:column;gap:8px}
.upload-audio-modes label{display:flex;align-items:center;gap:6px;cursor:pointer}
/* Доступ показывается отдельной колонкой только для одного выбранного
   кликом пользователя (см. app.js renderAdminGrantsPanel), не для всех сразу. */
.admin-users-area{display:flex;gap:14px;align-items:flex-start;margin-bottom:14px}
.admin-users-list{display:flex;flex-direction:column;gap:8px;overflow-y:auto;flex:1.3;min-width:0;max-height:52vh}
.admin-grants-panel{flex:1;min-width:0;max-height:52vh;overflow-y:auto;background:var(--bg3);border-radius:8px;padding:14px}
.admin-grants-panel h3{margin-bottom:10px;font-size:13px;color:var(--accent2);text-transform:none;letter-spacing:normal}
.admin-grants-list{display:flex;flex-direction:column;gap:2px}
.admin-grants-list label{display:flex;align-items:center;gap:8px;padding:5px 6px;border-radius:6px;cursor:pointer}
.admin-grants-list label:hover{background:var(--hover)}
.admin-user-row{background:var(--bg3);box-shadow:var(--card-shadow);border-radius:8px;padding:8px 10px;display:flex;flex-direction:column;gap:6px;cursor:pointer;border:1px solid transparent}
.admin-user-row:hover{border-color:var(--input-brd)}
.admin-user-row.selected{border-color:var(--accent2)}
.admin-user-row.blocked{opacity:.55}
.admin-user-top{display:flex;align-items:center;gap:8px}
.admin-user-login{font-weight:600;flex:1}
.admin-user-fields{display:flex;gap:8px}
.admin-user-fields input{flex:1;font-size:13px;padding:4px 8px}
.admin-user-bottom{display:flex;align-items:center;justify-content:space-between;gap:8px}
.admin-last-seen{font-size:12px}
.admin-new-user-form{display:flex}
.admin-fio-picker{position:relative;flex:1;min-width:120px}
.admin-fio-picker input{width:100%;box-sizing:border-box}
.admin-fio-list{display:none;position:absolute;top:100%;left:0;right:0;z-index:60;max-height:220px;overflow-y:auto;background:var(--bg2);border:1px solid var(--input-brd);border-radius:0 0 6px 6px;box-shadow:0 4px 12px rgba(0,0,0,.35);margin-top:-1px}
.admin-fio-picker.open .admin-fio-list{display:block}
.admin-fio-item{padding:6px 9px;font-size:13px;cursor:pointer;border-bottom:1px solid var(--border)}
.admin-fio-item:hover{background:var(--hover)}
.admin-fio-item .admin-fio-pos{display:block;font-size:11px;color:var(--text-dim)}
@media (max-width:700px){
  .admin-users-area{flex-direction:column}
  .admin-users-list,.admin-grants-panel{max-height:38vh;flex:none;width:100%}
}
.admin-fio-item.admin-fio-none{cursor:default;color:var(--text-dim);font-style:italic}
.admin-fio-item.admin-fio-none:hover{background:none}

/* header + tabs */
header{background:var(--bg2);padding:12px 20px;display:flex;align-items:center;gap:12px;border-bottom:2px solid var(--border)}
#ws-status{font-size:12px;padding:3px 8px;border-radius:10px;background:var(--bg3);color:var(--text-muted);white-space:nowrap;flex-shrink:0}
#ws-status.ok{background:#1a4d2e;color:var(--ok)}
#ws-status.err{background:#4d1a1a;color:var(--err)}
#user-badge{font-size:13px;color:var(--text-muted)}
/* по строке на ПК пула: при одном узле выглядит ровно как раньше */
.mini-gauges{display:flex;flex-direction:column;gap:3px;margin-left:16px}
.node-load{display:flex;align-items:center;gap:8px}
.node-load.offline{opacity:.45}
.node-name{font-size:10px;font-weight:700;letter-spacing:.4px;color:var(--text-dim);width:62px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.node-load.local .node-name{color:var(--text-muted)}
.node-jobs{font-size:10px;font-family:monospace;color:var(--accent)}
.mini-gauge{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--text-muted)}
.mg-label{font-weight:600;width:28px}
.mg-bar{background:var(--bg3);border-radius:3px;height:6px;width:48px;overflow:hidden}
.mg-bar div{height:100%;width:0;transition:width .4s,background .4s;background:var(--ok)}
.mg-val{width:32px;text-align:right;font-family:monospace}
@media (max-width:1300px){.mg-bar{width:32px}.node-name{width:48px}}
@media (max-width:900px){.mini-gauges{display:none}}
.load-stats{display:flex;gap:12px;margin-left:14px;font-size:12px;color:var(--text-muted)}
.load-stat b{color:var(--text);font-weight:600}
@media (max-width:1000px){.load-stats{display:none}}
.header-svcs{display:flex;flex-wrap:wrap;gap:6px;margin-left:6px}
.hsvc-pill{font-size:10px;padding:2px 7px;border-radius:8px;background:var(--bg3);color:var(--text-dim);cursor:default}
.hsvc-pill.ok{color:var(--ok)}
.hsvc-pill.warn{color:var(--warn)}
.hsvc-pill.err{color:var(--err)}
@media (max-width:1200px){.header-svcs{display:none}}
.startup-banner{display:flex;align-items:center;gap:14px;padding:12px 20px;background:#3a2a1a;color:#ffb74d;border-bottom:1px solid var(--border)}
.startup-banner .dim{color:#ffcc80}
.spinner{width:20px;height:20px;border-radius:50%;border:3px solid rgba(255,183,77,.3);border-top-color:#ffb74d;animation:spin 0.8s linear infinite;flex-shrink:0}
@keyframes spin{to{transform:rotate(360deg)}}
.tabs{display:flex;gap:2px;padding:0 20px;background:var(--bg2);border-bottom:1px solid var(--border)}
.tab{background:none;border-radius:0;padding:12px 18px;color:var(--text-muted);border-bottom:2px solid transparent}
.tab.active{color:var(--accent);border-bottom-color:var(--accent)}
.tab-body{display:none;padding:20px}
.tab-body.active{display:block}
.panel{background:var(--card-bg);box-shadow:var(--card-shadow);border-radius:10px;padding:20px;margin-bottom:16px}
.row{display:flex;align-items:center;gap:12px;margin-bottom:14px;flex-wrap:wrap}
.row>label{min-width:150px;color:var(--text-muted)}
.lang-checks{display:flex;gap:16px}
.lang-checks label{color:var(--text)}
.src-list{display:flex;flex-direction:column;gap:6px;flex:1}
.src-list label{display:flex;align-items:center;gap:8px;color:var(--text)}
.src-item{background:var(--bg3);padding:6px 10px;border-radius:6px}

/* live */
.live-head{display:flex;align-items:center;gap:10px;margin-bottom:14px;flex-wrap:wrap}
.rec-dot{width:12px;height:12px;border-radius:50%;background:var(--err);animation:pulse 1.2s infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.3}}
select.inline{padding:4px 8px}
.janna-ind{font-size:12px;padding:3px 10px;border-radius:10px;background:var(--bg3)}
.janna-ind.speaking{background:#1a4d2e;color:var(--ok)}
.janna-ind.thinking{background:#3a2a1a;color:var(--warn)}
.janna-ind.paused{background:#4d1a1a;color:var(--err)}
.btn-inline-spinner{width:12px;height:12px;border-radius:50%;border:2px solid color-mix(in srgb, var(--text) 28%, transparent);border-top-color:var(--text);display:inline-block;vertical-align:middle;animation:spin .8s linear infinite;margin-left:6px}
.live-cols{display:flex;gap:16px;align-items:flex-start}
.transcript-col{flex:2;min-width:0}
.side-col{flex:1;min-width:220px;display:flex;flex-direction:column;gap:16px}
.side-block{background:var(--card-bg);box-shadow:var(--card-shadow);border-radius:10px;padding:14px}
/* «Плавающее окно» спикеров — во время встречи карточки нужно видеть и
   таскать (drag&drop, см. attachUttDragDrop/renderSpeakers в app.js), не
   теряя их среди прокрутки остальной боковой колонки. left/top задаются
   инлайн из JS (перетаскивание за #speakers-float-handle, позиция
   запоминается в localStorage) — здесь только сам факт «оторван от потока». */
.side-block.floating{position:fixed;top:80px;right:20px;width:280px;z-index:50;
  box-shadow:0 8px 24px color-mix(in srgb, #000 40%, transparent)}
.side-block.floating #speakers-list{max-height:60vh}
#speakers-float-handle{cursor:default;user-select:none}
.side-block.floating #speakers-float-handle{cursor:move}
.collapsible-h3{cursor:pointer;user-select:none}
#resume-live-content{max-height:40vh;overflow-y:auto;font-size:13px}
#resume-live-content.collapsed{display:none}
#transcript{display:flex;flex-direction:column;gap:10px;min-height:300px;max-height:60vh;overflow-y:auto}
.utt{background:var(--card-bg);box-shadow:var(--card-shadow);border-left:3px solid var(--spk-color,var(--border));border-radius:8px;padding:8px 12px;transition:background .2s}
/* спикер опознан по слепку голоса из «Персоналий», а не назван вручную */
.spk-voice-badge{font-size:11px;font-weight:500;padding:1px 6px;border-radius:8px;background:var(--bg3);color:var(--accent2);white-space:nowrap}
.utt .spk{font-size:12px;font-weight:600;margin-bottom:2px;display:flex;align-items:center;gap:6px;flex-wrap:wrap}
/* кнопка слепка у реплики не должна лезть в глаза — показываем при наведении
   на реплику (на тач-устройствах hover не срабатывает, поэтому там видна всегда) */
.utt .btn-utt-voiceprint{margin-left:auto;font-size:11px;padding:2px 8px;opacity:0;transition:opacity .15s}
.utt:hover .btn-utt-voiceprint,.utt .btn-utt-voiceprint:focus{opacity:1}
@media (hover:none){.utt .btn-utt-voiceprint{opacity:.7}}
.utt-meta{display:flex;align-items:baseline;gap:8px;margin-bottom:2px}
.utt-meta .spk{margin-bottom:0}
.utt .ts,.utt-meta .ts{font-size:11px;font-weight:400;color:var(--text-dim);font-variant-numeric:tabular-nums}
.utt .ts{cursor:pointer}
.utt .ts:hover{color:var(--accent2);text-decoration:underline}
.utt .txt{color:var(--text)}
.utt.pending .txt{color:var(--text-muted)}
.utt.playing{background:var(--hover);box-shadow:0 0 0 1px var(--accent2), var(--card-shadow)}
.utt.unverified{border-left-color:var(--warn)}
.utt.unverified .txt::after{content:" ⚠";font-size:11px;opacity:.7}
.utt.utt-grouped{margin-top:-10px;padding-top:3px;border-top-left-radius:0;border-top-right-radius:0}
.utt.utt-grouped .utt-meta{display:none}
.utt:has(+ .utt.utt-grouped){border-bottom-left-radius:0;border-bottom-right-radius:0;padding-bottom:3px}
.unverified-text{border-bottom:1px dashed var(--warn)}
.debug-block{margin-top:6px;padding:6px 8px;border-radius:6px;background:var(--bg2);font-family:monospace;font-size:11px;line-height:1.5}
.debug-block b{color:var(--accent2)}
#hist-transcript{display:flex;flex-direction:column;gap:10px}
.hist-speakers{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px;max-height:100px;overflow-y:auto;padding-right:4px;scrollbar-width:thin}
.hist-speakers .speaker-chip{margin-bottom:0}
.retranscribe-row{display:flex;align-items:center;flex-wrap:wrap;gap:10px;margin-bottom:14px}
/* пока запись не переразобрана «точным режимом» — кнопка не должна теряться
   среди прочих secondary-кнопок, иначе про неё забывают (реальная жалоба
   пользователя — «сливается со всеми») */
button.btn-retranscribe-suggest{border:1.5px solid var(--warn);color:var(--warn);font-weight:600;background:var(--bg3)}
button.btn-retranscribe-suggest:hover{background:var(--warn);color:#1a1a1a}
.retranscribe-hint{font-size:12px}
/* подсказка pyannote о числе говорящих — пусто = решает сама (как раньше) */
.retranscribe-nspk{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--text-muted);white-space:nowrap}
.retranscribe-nspk input{width:70px;padding:4px 8px;font-size:12px}
.retranscribe-progress{display:flex;align-items:center;gap:8px}
.retranscribe-progress .progress-bar{width:140px;height:8px;background:var(--bg2);border-radius:4px;overflow:hidden}
.retranscribe-progress .progress-bar>div{height:100%;width:0;background:var(--accent2);transition:width .5s}
.retranscribe-progress span{font-size:12px;white-space:nowrap}
.live-doc-upload-progress{margin-top:8px;padding:8px 10px;background:var(--bg3);border:1px solid var(--input-brd);border-radius:8px}
.live-doc-upload-head{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:12px;margin-bottom:6px}
.live-doc-upload-head span:first-child{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.live-doc-upload-head span:last-child{font-variant-numeric:tabular-nums;color:var(--accent2)}
.live-doc-upload-progress .progress-bar{height:8px;background:var(--bg2);border-radius:4px;overflow:hidden}
.live-doc-upload-progress .progress-bar>div{height:100%;width:0;background:var(--accent2);transition:width .2s linear}
.live-doc-upload-progress.indeterminate .progress-bar>div{position:relative;animation:live-doc-upload-indeterminate 1.1s ease-in-out infinite}
.live-doc-upload-progress #live-doc-upload-progress-text{margin-top:6px;font-size:12px}
@keyframes live-doc-upload-indeterminate{0%{margin-left:-35%;width:35%}50%{margin-left:40%;width:45%}100%{margin-left:100%;width:30%}}
.btn-docx-link{text-decoration:none}
.utt .tr{color:var(--accent2);font-size:13px;font-style:italic;margin-top:4px;border-top:1px dashed var(--border);padding-top:4px}
#partials{margin-bottom:10px;color:var(--text-dim);font-style:italic;min-height:24px}
.partial-line{margin-top:4px}
.speaker-chip{display:flex;align-items:center;gap:8px;padding:6px;border-radius:6px;cursor:grab;margin-bottom:6px}
.speaker-chip:hover{background:var(--hover)}
.utt.drop-target{outline:2px dashed var(--accent2);outline-offset:2px}
.speaker-chip.drop-target{outline:2px dashed var(--accent2);outline-offset:2px}
.spk-icon{width:28px;height:28px;border-radius:50%;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700;font-size:13px;flex-shrink:0}
.spk-meta{font-size:12px;color:var(--text-muted)}
.speaker-chip-ai{cursor:default;border:1px dashed var(--accent2);background:var(--hover)}
.spk-icon-ai{background:var(--bg2);font-size:15px}
.speaker-chip-add{cursor:pointer;border:1px dashed var(--text-muted)}
.speaker-chip-add .spk-icon{background:var(--bg2);color:var(--text-muted);font-size:18px}
.speaker-chip-add:hover{border-color:var(--accent2)}
.ai-badge{font-size:10px;font-weight:700;color:var(--accent2);border:1px solid var(--accent2);border-radius:8px;padding:0 5px;vertical-align:middle;margin-left:2px}
.spk-langs{display:flex;gap:3px;margin-top:2px}
.spk-lang-btn{font-size:10px;font-weight:700;line-height:1;padding:2px 3px;border-radius:5px;border:1px solid var(--border);background:var(--bg2);color:var(--text-muted);cursor:pointer}
.spk-lang-btn:hover{border-color:var(--accent2);color:var(--text)}
#reco-list{max-height:40vh;overflow-y:auto}
/* раньше #speakers-list не имел собственного max-height/overflow на десктопе
   (в отличие от #reco-list/#transcript) — при накоплении карточек спикеров
   растягивал .side-block и всю страницу целиком; теперь скроллится сам,
   как и остальные списки в live-панели */
#speakers-list{max-height:40vh;overflow-y:auto}
.reco-item{background:var(--bg3);border-radius:6px;padding:8px 10px;margin-bottom:8px;font-size:13px;transition:background 1.5s,box-shadow 1.5s}
.reco-item.fresh{background:color-mix(in srgb, var(--accent2) 18%, var(--bg3));box-shadow:0 0 0 1px var(--accent2);animation:reco-pop .25s ease-out}
@keyframes reco-pop{from{transform:translateY(-6px);opacity:0}to{transform:none;opacity:1}}
.janna-ind.thinking{animation:jn-pulse 1.2s ease-in-out infinite}
@keyframes jn-pulse{0%,100%{opacity:1}50%{opacity:.45}}

/* history */
.hist-wrap{display:flex;gap:16px;align-items:flex-start}
.hist-list-col{flex:0 0 320px;width:320px;display:flex;flex-direction:column;gap:8px}
.hist-search{width:100%}
.hist-list{display:flex;flex-direction:column;gap:8px;
  max-height:var(--hist-list-max, calc(100vh - 270px));overflow-y:auto}
.hist-sentinel{flex:0 0 1px;height:1px}
.hist-card{background:var(--card-bg);box-shadow:var(--card-shadow);border:1px solid transparent;border-radius:8px;padding:12px;cursor:pointer}
.hist-card-head{display:flex;align-items:flex-start;gap:8px}
.hist-mode-icon{flex-shrink:0;margin-top:1px;color:var(--text-muted)}
.hist-card b{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
.hist-card:hover{border-color:var(--accent2)}
.hist-card.active{border-color:var(--accent);background:var(--hover);box-shadow:0 0 0 2px var(--accent) inset, var(--card-shadow)}
.hist-card.hist-card-live{border-color:var(--err)}
.hist-card mark,#hist-transcript mark{background:rgba(255,183,77,.45);color:inherit;border-radius:2px;padding:0 1px}
.hist-snippet{font-size:12px;color:var(--text-dim);margin-top:4px;font-style:italic}
.hist-live-badge{display:inline-flex;align-items:center;gap:5px;margin-left:auto;flex-shrink:0;font-size:12px;font-weight:700;color:var(--err)}
.hist-live-banner{display:flex;align-items:center;gap:8px;font-size:13px;font-weight:600;color:var(--err);
  background:color-mix(in srgb, var(--err) 12%, transparent);border-radius:8px;padding:8px 12px;margin-bottom:10px}
.hist-detail{flex:2;background:var(--card-bg);box-shadow:var(--card-shadow);border-radius:10px;padding:20px;min-height:300px;display:flex;flex-direction:column;
  max-height:var(--hist-detail-max, calc(100vh - 220px))}
.summary-box{background:var(--bg3);border-radius:8px;padding:12px;margin:12px 0}
.summary-box ul{margin-left:18px}
.summary-editable-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:8px}
.summary-editable-head h3{margin-bottom:0}
.summary-edited-badge{font-size:12px}
.summary-edit-form h3{margin-top:16px}
.summary-edit-form h3:first-child{margin-top:0}
.se-field{width:100%;min-height:90px;font-family:inherit;margin-bottom:4px}
.se-group{background:var(--bg2);border-radius:8px;padding:10px;margin-bottom:10px}
.se-group-head{display:flex;gap:8px;margin-bottom:8px}
.se-group-head .se-org{flex:1}
.se-people{display:flex;flex-direction:column;gap:6px;margin-bottom:8px}
.se-person,.se-list-item,.se-task-row,.se-comp-row{display:flex;gap:8px;margin-bottom:6px}
.se-person input,.se-list-item input,.se-task-row input{flex:1;min-width:0}
.se-opinion-row,.se-roadmap-row{display:flex;flex-direction:column;gap:6px;padding:10px;margin-bottom:10px;background:var(--bg2);border-radius:8px;position:relative}
.se-opinion-row .se-remove,.se-roadmap-row .se-remove{position:absolute;top:8px;right:8px}
.se-opinion-row .se-opinion-proposal,.se-roadmap-row .se-roadmap-step{width:100%;padding-right:34px;font-weight:600}
.se-opinion-row .se-opinion-opinion,.se-roadmap-row .se-roadmap-details{width:100%;min-height:110px;resize:vertical;font-family:inherit}
.se-comp-row .se-comp-name{flex:2;min-width:0}
.se-comp-row .se-comp-status{flex:0 0 190px}
.se-comp-row .se-comp-evidence{flex:3;min-width:0}
.se-list{margin-bottom:4px}

/* calendar */
.cal-head{display:flex;align-items:center;gap:12px;margin-bottom:14px}
.cal-head b{font-size:16px;min-width:160px;text-align:center}
.cal-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:6px}
.cal-weekday{text-align:center;font-size:12px;color:var(--text-dim);padding:4px 0}
.cal-cell{background:var(--card-bg);box-shadow:var(--card-shadow);border:1px solid transparent;border-radius:8px;
  height:110px;padding:6px;display:flex;flex-direction:column;gap:4px;overflow-y:auto}
.cal-cell.cal-empty{background:transparent;border-color:transparent;box-shadow:none}
.cal-cell.cal-today{border-color:var(--accent)}
.cal-weekday.cal-weekend{color:var(--err)}
.cal-cell.cal-weekend{background:var(--weekend-bg)}
.cal-cell.cal-weekend.cal-today{border-color:var(--accent);background:var(--weekend-bg)}
.cal-daynum{font-size:12px;color:var(--text-dim);flex-shrink:0}
.cal-chip{background:var(--bg3);border-radius:5px;padding:2px 6px 2px 5px;font-size:12px;cursor:pointer;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0;
  border-left:3px solid var(--spk-color,var(--border))}
.cal-chip:hover{background:var(--hover);color:var(--accent2)}
.cal-chip-project-dot{display:inline-block;width:7px;height:7px;border-radius:50%;margin-right:4px}
.cal-modal-card{width:60vw;max-width:900px;min-height:55vh;max-height:70vh;padding:36px}
.cal-modal-card h1{font-size:24px}
.cal-modal-card .dim{font-size:15px}
.cal-modal-summary{overflow-y:auto;flex:1;white-space:pre-wrap;background:var(--bg3);border-radius:8px;
  padding:18px 22px;font-size:16px;line-height:1.65}
@media (max-width:700px){
  .cal-modal-card{width:92vw;max-height:75vh}
}
@media (max-width:700px){
  .cal-cell{height:70px}
  .cal-head b{min-width:120px}
}
.tasks-table{width:100%;border-collapse:collapse;font-size:13px;margin-top:6px}
.tasks-table th,.tasks-table td{border:1px solid var(--border);padding:6px 10px;text-align:left}
.tasks-table th{background:var(--bg2);color:var(--text-muted);font-weight:600}
.participants-groups{display:flex;flex-wrap:wrap;gap:14px;margin-top:6px}
.participants-group{background:var(--bg2);border-radius:8px;padding:8px 12px;min-width:160px}
.participants-group ul{margin:4px 0 0 18px}
.ai-opinion-list{display:flex;flex-direction:column;gap:10px;margin-top:6px}
.ai-opinion-item{background:var(--bg2);border-radius:8px;padding:8px 12px;border-left:3px solid var(--accent2)}
.ai-opinion-item p{margin:4px 0 0}
.hist-title-row{display:flex;align-items:center;justify-content:space-between;gap:14px;margin-bottom:8px;flex-shrink:0}
.hist-title-row h2{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0}
.hist-title-row button{flex-shrink:0}
.hist-actions-row{display:flex;align-items:center;gap:14px;margin-bottom:12px;flex-shrink:0}
.project-search-row{display:flex;align-items:center;gap:14px}
.hist-actions-row audio{flex:0 0 260px;width:260px;height:30px;transition:flex-basis .35s ease,width .35s ease}
.hist-actions-row.audio-playing audio{flex-basis:100%;width:100%}
.hist-actions-extra{display:flex;flex-wrap:wrap;align-items:center;gap:14px;flex:1;min-width:0;opacity:1;
  transition:opacity .3s ease,flex .35s ease}
.hist-actions-extra button{flex-shrink:0}
.hist-actions-row.audio-playing .hist-actions-extra{opacity:0;flex:0 0 0;gap:0;overflow:hidden;pointer-events:none;flex-wrap:nowrap}
.editable-title{cursor:pointer;border-bottom:1px dashed transparent}
.editable-title:hover{border-bottom-color:var(--accent2)}
.title-edit-input{font-size:18px;font-weight:700;flex:1;min-width:0}
.hist-tabs{display:flex;align-items:center;gap:4px;margin-bottom:12px;flex-shrink:0;border-bottom:1px solid var(--border)}
.hist-subtab{background:none;border-radius:0;padding:8px 14px;color:var(--text-muted);border-bottom:2px solid transparent}
.hist-subtab.active{color:var(--accent);border-bottom-color:var(--accent)}
.hist-pane{display:none;flex:1;min-height:0}
.hist-pane.active{display:block;overflow-y:auto}
#hist-pane-transcript.active{display:flex;flex-direction:column;overflow:hidden}
.hist-speakers{flex-shrink:0}
#hist-transcript{flex:1;overflow-y:auto;min-height:0}

/* персоналии */
.persona-card{background:var(--bg3);box-shadow:var(--card-shadow);border-radius:10px;padding:14px;margin-bottom:12px}
.persona-head{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.persona-appearance{border-top:1px dashed var(--border);padding:8px 0}
.persona-appearance:first-child{border-top:none;padding-top:0}
.persona-profile{background:var(--bg2);border-left:3px solid var(--accent2);border-radius:6px;padding:10px 12px;margin-bottom:10px}
.persona-chars.collapsed{display:none}
.persona-posorg{cursor:pointer;margin-bottom:10px;font-size:13px}
.persona-posorg:hover{text-decoration:underline}
.persona-posorg-edit{display:flex;gap:8px;margin-bottom:10px}
.persona-posorg-edit input{flex:1}
.persona-name{cursor:pointer}
.persona-name:hover{text-decoration:underline}
.persona-name-edit{font-weight:600}
.persona-appearance-link{cursor:pointer;border-radius:6px;margin:0 -6px;padding:8px 6px}
.persona-appearance-link:hover{background:var(--hover)}
.char-ai-note{color:var(--text-dim);font-style:italic;font-size:13px;margin-top:4px}

/* проекты */
.project-card{background:var(--bg3);box-shadow:var(--card-shadow);border-radius:10px;padding:14px;margin-bottom:12px}
.project-card.stale{border-left:3px solid var(--warn,#ffb74d)}
.project-head{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.project-thumb{width:44px;height:44px;border-radius:8px;object-fit:cover;flex-shrink:0}
.project-thumb-placeholder{display:flex;align-items:center;justify-content:center;font-weight:600;color:#fff;font-size:18px}
.project-name{cursor:pointer}
.project-name:hover{text-decoration:underline}
.project-analysis{background:var(--bg2);border-left:3px solid var(--accent2);border-radius:6px;padding:10px 12px;margin-bottom:10px}
.project-analysis h4{margin:8px 0 4px}
.risk-table{width:100%;border-collapse:collapse;font-size:13px}
.risk-table th,.risk-table td{border:1px solid var(--border);padding:6px 10px;text-align:left;vertical-align:top}
.risk-table th{background:var(--bg3);color:var(--text-muted);font-weight:600}
.risk-row.risk-high td{background:rgba(244,67,54,.14);border-left:3px solid var(--err)}
.risk-row.risk-medium td{background:rgba(255,179,0,.16);border-left:3px solid var(--warn)}
.risk-row.risk-low td{background:rgba(76,175,80,.14);border-left:3px solid var(--ok)}
.risk-row td:not(:first-child){border-left:1px solid var(--border)}
.req-row.req-confirmed td{background:rgba(76,175,80,.14);border-left:3px solid var(--ok)}
.req-row.req-partial td{background:rgba(255,179,0,.16);border-left:3px solid var(--warn)}
.req-row.req-not-confirmed td{background:rgba(244,67,54,.14);border-left:3px solid var(--err)}
.req-row.req-unknown td{border-left:3px solid var(--border)}
.req-row td:not(:first-child){border-left:1px solid var(--border)}
.project-analysis h4:first-child{margin-top:0}
.project-meetings.collapsed{display:none}
.project-analysis-wrap.collapsed{display:none}
.project-documents.collapsed{display:none}
.project-meeting-link{cursor:pointer;border-radius:6px;margin:0 -6px;padding:6px}
.project-meeting-link:hover{background:var(--hover)}
.project-doc-item{display:flex;align-items:center;gap:8px;padding:6px 0;border-bottom:1px solid var(--border)}
.project-doc-item:last-child{border-bottom:none}
.project-doc-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.project-doc-meta{color:var(--text-dim);font-size:12px;flex-shrink:0}
.project-doc-upload-row{margin-top:8px}
.project-roadmap.collapsed{display:none}
.project-task-row{display:flex;align-items:center;gap:8px;padding:6px 0;border-bottom:1px solid var(--border);flex-wrap:wrap}
.project-task-row:last-child{border-bottom:none}
.project-task-title{flex:1;min-width:140px}
.project-task-assignee{width:140px}
.project-task-start,.project-task-end{width:130px}
.project-task-status{width:150px}
.project-task-src{flex-shrink:0;font-size:14px;cursor:help}
.project-task-up,.project-task-down{padding:2px 8px}
.project-task-add-row{display:flex;align-items:center;gap:8px;margin-top:10px;flex-wrap:wrap}
.project-task-new-title{flex:1;min-width:140px}
.project-task-new-assignee{width:140px}
.project-task-new-start,.project-task-new-end{width:130px}
.project-analyses-history.collapsed{display:none}
.project-history-item{border-bottom:1px solid var(--border);padding:8px 0}
.project-history-item:last-child{border-bottom:none}
.project-history-item-head{display:flex;align-items:center;gap:8px}
.project-history-item-toggle{cursor:pointer}
.project-history-item-toggle:hover{text-decoration:underline}
.project-history-item-body{margin-top:8px}
.project-history-item-body.collapsed{display:none}
.project-modal-card{width:60vw;max-width:900px;padding:36px;gap:16px}
@media (max-width:700px){
  .project-modal-card{width:92vw}
}
.project-color-picker{display:flex;flex-wrap:wrap;gap:8px;margin:4px 0}
.project-color-swatch{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid transparent}
.project-color-swatch.selected{border-color:var(--text)}
.project-image-row{display:flex;align-items:center;gap:12px}
.project-remove-image-link{cursor:pointer;margin-top:6px}
.project-remove-image-link:hover{text-decoration:underline}
.hist-project-badge{display:inline-block;border-radius:10px;padding:1px 8px;font-size:12px;color:#fff;margin-top:2px}
.project-access-list{max-height:40vh;overflow-y:auto;display:flex;flex-direction:column;gap:6px}
.project-access-row{display:flex;align-items:center;gap:8px}
.project-access-row.owner{opacity:.6}

/* участники встречи (экран настройки) */
.participant-row{display:flex;gap:8px;align-items:center;margin-bottom:6px}
.participant-row .admin-fio-picker{flex:1}
.participant-meta{position:absolute;right:12px;top:50%;transform:translateY(-50%);
  pointer-events:none;font-size:12px;max-width:55%;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}

/* термины */
.term-add-row{display:flex;gap:8px;margin-bottom:16px}
.term-add-row input{flex:1}
.term-add-row input.term-new-canonical{flex:0 0 18%}
.term-card{background:var(--bg3);box-shadow:var(--card-shadow);border-radius:10px;padding:14px;margin-bottom:12px}
.term-head{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.term-canonical{cursor:pointer}
.term-canonical:hover{text-decoration:underline}
.term-canonical-edit{font-weight:600}
.term-variants{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px}
.term-variant-chip{display:flex;align-items:center;gap:6px;background:var(--bg2);box-shadow:var(--card-shadow);border-radius:20px;padding:4px 10px;font-size:13px}
.term-variant-chip .chip-del{cursor:pointer;opacity:.6}
.term-variant-chip .chip-del:hover{opacity:1}
.term-variant-add{display:flex;gap:8px}
.term-variant-add input{flex:1}

/* prompts */
.prompt-wrap{display:flex;gap:16px;align-items:flex-start}
.prompt-tabs-col{display:flex;flex-direction:column;gap:8px;min-width:200px}
.prompt-advanced-toggle{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--text-muted);cursor:pointer}
.prompt-tabs{display:flex;flex-direction:column;gap:4px;max-height:var(--prompt-tabs-max, calc(100vh - 270px));overflow-y:auto}
.prompt-tabs button{text-align:left;background:var(--card-bg);box-shadow:var(--card-shadow);border:1px solid transparent}
.prompt-tabs button.active{border-color:var(--accent);color:var(--accent)}
.prompt-tabs button.advanced-tab{background:var(--input-bg-warn)}
.prompt-tabs button.advanced-tab.active{border-color:var(--warn);color:var(--text)}
.prompt-tabs button.custom-tab{position:relative}
.prompt-tabs button.custom-tab::after{content:'';position:absolute;top:7px;right:8px;width:7px;height:7px;border-radius:50%;background:var(--accent)}
.prompt-editor{flex:1;display:flex;flex-direction:column;gap:10px}
.prompt-desc{background:var(--bg3);border-radius:8px;padding:10px 14px;font-size:13px;color:var(--text-muted)}
#prompt-text{width:100%;min-height:340px;font-family:'Cascadia Code',Consolas,monospace;resize:vertical}
#prompt-text.advanced{background:var(--input-bg-warn);border-color:var(--warn)}
.prompt-actions{display:flex;gap:10px;align-items:center}

.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);background:var(--card-bg);border-radius:8px;padding:10px 18px;opacity:0;transition:opacity .3s;pointer-events:none;z-index:2000;box-shadow:0 4px 16px rgba(0,0,0,.3)}
.toast.show{opacity:1}
.sel-speaker-tip{position:fixed;display:flex;flex-wrap:wrap;align-items:center;gap:6px;max-width:320px;
  background:var(--card-bg);border-radius:8px;padding:8px;z-index:2100;
  box-shadow:0 4px 16px rgba(0,0,0,.35)}
.sel-speaker-tip-label{width:100%;font-size:12px;color:var(--text-muted)}
.sel-speaker-chip{padding:4px 10px;border-radius:14px;font-size:13px;background:var(--bg2);
  border:1px solid var(--spk-color, var(--border));color:var(--text)}
.sel-speaker-chip:hover{background:var(--hover)}

/* Кнопка старта и её свечение (.wv-start-wrap) — не потомки overflow-y:auto
   контейнера (тот скролл только на .wv-scroll): в части браузеров блюр
   свечения раздувает scrollHeight родителя и рисует лишний скроллбар, даже
   будучи чисто визуальным эффектом. */
.webview-panel{display:flex;flex-direction:column;flex:1;min-height:0;gap:16px;padding:0 0 8px}
/* justify-content:flex-start, не center: иначе при контенте выше экрана
   (роль «Собеседование») верх формы уходит за пределы скролла — scrollTop
   не может стать отрицательным, и его не долистать. */
.wv-scroll{display:flex;flex-direction:column;align-items:center;justify-content:flex-start;
  gap:36px;flex:1;min-height:0;overflow-y:auto;padding:12px 0 0;touch-action:pan-y}
/* .wv-compact центрирует контент вертикально для роли «Ассистент» (без доп.
   полей, всегда помещается на экран); «Собеседование» его снимает в
   setupWebviewUI() — см. justify-content:flex-start выше. */
.webview-panel.wv-compact .wv-scroll{justify-content:center}
.wv-row{display:flex;gap:14px;flex-wrap:wrap;justify-content:center;flex-shrink:0}
.wv-icon-btn{background:var(--card-bg);border:2px solid var(--border);border-radius:16px;
  width:64px;height:64px;display:flex;flex-direction:column;align-items:center;justify-content:center;
  padding:0;gap:4px;line-height:1;flex-shrink:0;color:var(--text-muted)}
.wv-icon-btn svg{width:26px;height:26px}
.wv-icon-btn span{font-size:10px;color:var(--text-muted)}
.wv-icon-btn.active{border-color:var(--accent2);background:var(--hover);box-shadow:0 0 0 2px var(--accent2) inset;color:var(--accent2)}

/* Карусель режимов (Ассистент/HR) — свайп, зациклена по краям клонами
   (см. index.html и initWvModeCarousel в app.js). */
.wv-mode-carousel{width:100%;max-width:420px;overflow:hidden;flex-shrink:0;touch-action:pan-y}
.wv-mode-track{display:flex;transition:transform .32s cubic-bezier(.22,.61,.36,1)}
.wv-mode-track.dragging{transition:none}
.wv-mode-slide{flex:0 0 100%;min-width:0;display:flex;flex-direction:column;align-items:center;
  gap:10px;padding:4px 8px;user-select:none}
.wv-mode-icon{width:80px;height:80px;display:flex;align-items:center;justify-content:center;
  color:var(--inverse-surface);flex-shrink:0}
.wv-mode-icon svg{width:48px;height:48px}
/* Анимация точек синхронна со свайпом (см. updateModeDots в app.js);
   transition отключается во время перетаскивания класом .dragging. */
.wv-mode-dots{display:flex;align-items:center;justify-content:center;gap:8px;flex-shrink:0}
.wv-mode-dot{width:6px;height:6px;border-radius:50%;background:var(--accent2);opacity:.75;
  transform:scale(1);transition:opacity .25s ease,transform .25s ease}
.wv-mode-dot.dragging{transition:none}
.wv-mode-dot.active{opacity:1;transform:scale(1.45)}

/* grid-template-rows 0fr→1fr анимирует раскрытие блока до auto-высоты контента
   (applyRole в app.js лишь toggle('wv-open')). !important снимает инлайновый
   style="display:none" из разметки, нужный десктопу. */
body.webview-mode #resume-block{
  display:grid !important; grid-template-rows:0fr; opacity:0; width:100%; max-width:420px;
  transition:grid-template-rows .4s cubic-bezier(.22,.61,.36,1), opacity .3s ease}
body.webview-mode #resume-block.wv-open{grid-template-rows:1fr; opacity:1}
/* overflow:hidden только пока блок схлопнут (0fr), чтобы скрыть переполняющий
   контент; снимается в открытом состоянии — иначе даже overflow-x:visible
   браузер трактует как auto раз overflow-y не visible, и тени .wv-doc-card
   обрезаются по границе бокса так же, как hidden.
   min-width:0 — явно, а не полагаясь на автоматический ноль от overflow:hidden:
   как только overflow снимается в .wv-open (см. правило ниже), у grid-элемента
   возвращается auto-минимум = min-content его содержимого, а длинное имя
   прикреплённого файла в .wv-doc-status (white-space:nowrap) в min-content НЕ
   обрезается своими же overflow/max-width (это чисто paint-время эффекты) —
   раздувает .wv-resume-inner на всю длину текста, карточка вылезает за экран
   и обрезается только на внешней карусели, уже без многоточия. */
body.webview-mode #resume-block .wv-resume-inner{overflow:hidden;min-height:0;min-width:0;
  display:flex;flex-direction:column;gap:14px}
body.webview-mode #resume-block.wv-open .wv-resume-inner{overflow:visible}
body.webview-mode #resume-block .row{flex-direction:column;align-items:stretch;gap:6px}
body.webview-mode #resume-block .row>label{min-width:0;font-size:12px;font-weight:600;color:var(--text-muted)}
body.webview-mode #btn-analyze-resume{width:100%}

/* Textarea/file-input внутри .wv-doc-card — реальные элементы, физически
   перенесённые сюда JS (setupWvDocCards), а не дубликаты: значение всегда
   одно и лежит там же, где его читает остальной код. setupWvDocCards()
   вызывается только в webview-режиме (см. applyRole в app.js) — на десктопе
   карточка так и остаётся пустой оболочкой рядом с обычной строкой
   file/textarea, поэтому вне webview-режима она скрыта. */
.wv-doc-card{display:none;position:relative;background:var(--card-bg);box-shadow:var(--card-shadow);border-radius:14px;
  padding:12px 14px;min-width:0;max-width:100%}
body.webview-mode .wv-doc-card{display:block}
.wv-doc-head{display:flex;align-items:center;gap:8px;min-width:0}
.wv-doc-title{font-size:13px;font-weight:600;color:var(--text)}
/* min-width:0 — тот же случай, что у .wv-resume-inner выше: без него длинное
   имя файла (nowrap) может тянуть ширину предков вверх по дереву в обход
   собственных overflow/max-width этого элемента. */
.wv-doc-status{margin-left:auto;font-size:12px;color:var(--text-dim);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;max-width:40%;min-width:0;transition:color .2s ease}
.wv-doc-card.has-value .wv-doc-status{color:var(--accent2)}
.wv-doc-actions{display:flex;gap:8px;margin-top:10px}
.wv-doc-btn{width:32px;height:32px;border-radius:50%;background:var(--bg3);color:var(--text-muted);
  display:flex;align-items:center;justify-content:center;padding:0;flex-shrink:0;
  transition:background .2s ease,color .2s ease,transform .15s ease}
.wv-doc-btn svg{width:16px;height:16px}
.wv-doc-btn:active{transform:scale(.92)}
.wv-doc-upload:hover,.wv-doc-pencil:hover{color:var(--accent2)}
.wv-doc-card.editing .wv-doc-pencil{background:var(--hover);color:var(--accent2)}
.wv-doc-clear{opacity:0;transform:scale(.6);pointer-events:none;
  transition:opacity .2s ease,transform .2s ease}
.wv-doc-card.has-value .wv-doc-clear{opacity:1;transform:scale(1);pointer-events:auto}
.wv-doc-clear:hover{color:var(--err)}
/* max-height вместо grid-rows (как у #resume-block выше): тут не единственный
   ребёнок родителя, а высота контента заранее известна с запасом. */
.wv-doc-editor{max-height:0;opacity:0;overflow:hidden;
  transition:max-height .32s ease,opacity .25s ease,margin-top .32s ease}
.wv-doc-card.editing .wv-doc-editor{max-height:160px;opacity:1;margin-top:10px}
.wv-doc-editor-slot textarea{width:100%}
.wv-doc-analyze-slot{max-height:0;opacity:0;overflow:hidden;
  transition:max-height .32s ease,opacity .25s ease,margin-top .32s ease}
.wv-doc-card.has-value .wv-doc-analyze-slot{max-height:600px;opacity:1;margin-top:10px}
/* Не display:none — в части браузеров теряется возможность программно
   .click() скрытый инпут; вместо этого визуально нулевые размеры. */
.wv-doc-hidden-file{position:absolute;width:1px;height:1px;opacity:0;overflow:hidden;pointer-events:none}

/* width/flex-shrink стоят на .wv-start-wrap, а не на кнопке внутри — кнопка
   не флекс-айтем сама по себе, эти свойства на ней не действуют. */
.wv-start-wrap{position:relative;width:100%;max-width:420px;flex-shrink:0;
  --wv-glow-c1:#2dc7fb; --wv-glow-c2:#ff0000; --wv-glow-c3:#d814ff;
  --wv-glow-blur:29px; --wv-glow-spread:19px; --wv-glow-opacity:0.25; --wv-glow-speed:1.5s}
/* Крутится угол conic-gradient (`from <angle>`), а не transform:rotate() на
   самом боксе — иначе широкая невысокая «пилюля» выглядит как крутящийся
   пропеллер вместо свечения вокруг кнопки. Нетипизированные custom properties
   не интерполируются плавно в анимации, поэтому --wv-glow-angle
   регистрируется через @property как <angle>. */
@property --wv-glow-angle{syntax:'<angle>';inherits:false;initial-value:0deg}
.wv-start-wrap::before{content:"";position:absolute;z-index:0;pointer-events:none;
  inset:calc(-1 * var(--wv-glow-spread));
  border-radius:calc(16px + var(--wv-glow-spread));
  background:conic-gradient(from var(--wv-glow-angle), var(--wv-glow-c1), var(--wv-glow-c2), var(--wv-glow-c3), var(--wv-glow-c1));
  filter:blur(var(--wv-glow-blur));
  opacity:var(--wv-glow-opacity);
  animation:wv-glow-spin var(--wv-glow-speed) linear infinite}
@keyframes wv-glow-spin{to{--wv-glow-angle:360deg}}
@media (prefers-reduced-motion: reduce){.wv-start-wrap::before{animation:none}}
.wv-start-btn{position:relative;z-index:1;width:100%;height:56px;border-radius:16px;
  background:var(--accent);color:var(--btn-primary-text);
  font-size:17px;font-weight:600;border:none}
.wv-start-btn:active{transform:scale(.98)}
body.webview-mode header,
body.webview-mode nav.tabs,
body.webview-mode #setup-panel{display:none !important}
/* webview — приложение, а не веб-страница: без зума и без выделения текста
   (кроме реальных полей ввода, где выделение нужно для редактирования) */
body.webview-mode{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}
body.webview-mode input,
body.webview-mode textarea{-webkit-user-select:text;user-select:text}
body.webview-mode button,
body.webview-mode a{-webkit-tap-highlight-color:transparent}
body.webview-mode button:focus,
body.webview-mode a:focus{outline:none}
/* Страница целиком не скроллится — только #transcript; иначе на мобильном
   (100vh не учитывает системные панели) страница скроллится целиком и
   .mobile-tabbar "плывёт" вместе с ней. 100dvh идёт после 100vh: старые
   браузеры игнорируют невалидное значение и остаются на 100vh. */
html.webview-mode,body.webview-mode{height:100vh;height:100dvh;overflow:hidden}
/* Как в реальном Android WebView — скролл работает, просто без видимого
   трека/ползунка. */
body.webview-mode,body.webview-mode *{scrollbar-width:none}
body.webview-mode *::-webkit-scrollbar{width:0;height:0;display:none}
/* !important снимает инлайновый #app{display:'block'}, который JS ставит
   при входе (boot() в app.js) */
body.webview-mode #app{height:100% !important;display:flex !important;flex-direction:column;overflow:hidden}
body.webview-mode #tab-meeting.active{flex:1;min-height:0;display:flex;flex-direction:column}
#webview-panel #resume-block,
#webview-panel #sync-block{width:100%;max-width:420px;text-align:left;flex-shrink:0}
.wv-recent{display:flex;flex-direction:column;gap:8px;width:100%;max-width:420px;flex-shrink:0}
.wv-recent-title{font-size:12px;color:var(--text-muted);text-align:center}
.wv-recent-list{display:flex;flex-direction:column;gap:6px}
.wv-recent-item{display:flex;align-items:center;gap:2px;width:100%;
  background:var(--card-bg);box-shadow:var(--card-shadow);border-radius:12px;
  padding:4px 4px 4px 12px;color:var(--text)}
.wv-recent-item-main{display:flex;align-items:center;gap:10px;flex:1;min-width:0;
  text-align:left;background:none;border:none;padding:8px 4px;margin:-4px 0;
  border-radius:8px;color:inherit;font:inherit}
.wv-recent-item-main:active{background:var(--hover)}
.wv-recent-item-del{flex-shrink:0;width:32px;height:32px;border:none;border-radius:50%;
  background:none;color:var(--text-muted);font-size:16px;line-height:1;
  display:flex;align-items:center;justify-content:center}
.wv-recent-item-del:active{background:var(--hover);color:var(--err)}
.wv-recent-item-text{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
.wv-recent-item-text b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wv-recent-item-text .dim{font-size:11px}
#webview-panel input,
#webview-panel select,
#webview-panel textarea{font-size:16px}

/* WebView: живой диалог — по одной панели за раз (свайп/нижние вкладки),
   крупнее шрифты и кнопки под палец вместо мыши */
.mobile-tabbar{display:none}
body.webview-mode #live-panel{font-size:16px}
/* Нижняя таб-панель (.mobile-tabbar) должна упираться в край экрана без
   зазора; свой отступ снизу для экрана старта даёт .webview-panel{padding:0 0 8px} */
body.webview-mode #tab-meeting.active{padding:8px 8px 0 8px}
body.webview-mode #live-panel.panel-flex{padding:10px 10px 0 10px;margin-bottom:0;background:none;box-shadow:none;border-radius:0}
body.webview-mode .live-head{flex-wrap:wrap;row-gap:6px;gap:4px}
/* Нативный <select> рендерится ОС-виджетом мимо темы приложения, поэтому в
   шапке встречи — пиктограммы. display кнопок остаётся под управлением JS
   (setJanna, setMeetingPaused, updateTakeoverUI); "иконка над подписью"
   делается вложенными .pic-ico/.pic-label, что работает при любом display
   самой кнопки. */
.live-pic-group{display:none}
body.webview-mode #live-mode,
body.webview-mode #live-length{display:none}
body.webview-mode .live-pic-group{display:flex;gap:4px}
body.webview-mode .live-pic-btn{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px}
body.webview-mode .live-head button{
  width:44px;height:44px;padding:3px;border-radius:11px;text-align:center;vertical-align:top;
  background:var(--bg2);border:2px solid transparent;flex-shrink:0}
body.webview-mode .live-head button .pic-ico{display:block;font-size:17px;line-height:1.25}
body.webview-mode .live-head button .pic-ico svg{width:17px;height:17px;display:block}
body.webview-mode .live-head button .pic-label{display:block;font-size:9px;color:var(--text-muted);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
body.webview-mode .live-pic-btn.active{border-color:var(--accent2);background:var(--hover)}
body.webview-mode .live-pic-btn.active .pic-ico{color:var(--accent2)}
body.webview-mode .live-pic-btn.active .pic-label{color:var(--accent2)}
body.webview-mode #btn-stop{background:var(--err);border-color:transparent}
body.webview-mode #btn-stop .pic-label{color:#fff}
.live-head button .pic-ico{margin-right:4px}
body.webview-mode .live-head button .pic-ico{margin-right:0}
/* .live-head-break — flex-элементы с flex-basis:100%, принудительно
   переносящие строку независимо от того, влезает ли она по ширине; order на
   остальных элементах определяет итоговую группировку строк (не DOM-порядок). */
.live-head-break{display:none}
body.webview-mode .live-head-break{display:block;flex-basis:100%;height:0}
body.webview-mode .rec-dot{order:1}
body.webview-mode #live-title{order:2}
body.webview-mode #meeting-timer{order:3;margin-left:auto}
body.webview-mode #live-break-1{order:4}
body.webview-mode #live-mode-pics{order:5}
body.webview-mode #live-break-2{order:6}
body.webview-mode #live-length-pics{order:7}
body.webview-mode #btn-meeting-pause,
body.webview-mode #btn-meeting-resume{order:8;margin-left:auto}
body.webview-mode #btn-stop{order:9}
body.webview-mode #live-break-3{order:10}
body.webview-mode #janna-ind,
body.webview-mode #btn-jn-pause,
body.webview-mode #btn-jn-resume,
body.webview-mode #btn-resume-system-capture,
body.webview-mode #viewer-badge,
body.webview-mode #btn-takeover,
body.webview-mode #meeting-paused-badge{order:11}
body.webview-mode .live-head .spacer{display:none}
body.webview-mode .utt{padding:12px 14px}
body.webview-mode .utt .txt{font-size:16px}
body.webview-mode .speaker-chip{padding:10px}
/* Жёсткий max-height от высоты экрана + overflow-y:auto — flex:1/min-height:0
   по цепочке родителей само по себе давало переполнение. Отступ подобран с
   запасом под .live-head (до 3 строк при переносе) + паддинги + #partials +
   .mobile-tabbar, точная высота которых заранее не известна. Паддинг + minus-
   margin дают тени .utt место для блюра — overflow:auto иначе клипует ровно
   по границе бокса. */
body.webview-mode #transcript{max-height:calc(100vh - 340px);max-height:calc(100dvh - 340px);min-height:0;flex:1;overflow-y:auto;padding:4px 8px;margin:0 -8px}
/* align-items:stretch обязателен: без него .live-cols наследует flex-start,
   .side-col получает высоту "по контенту" вместо растянутой на экран, и
   flex:1/min-height:0 на #speakers-list/#reco-list ничего не скроллит —
   контент просто обрезается снаружи без скроллбара. */
body.webview-mode .live-cols{flex:1;min-height:0;display:flex;align-items:stretch}
body.webview-mode .transcript-col{display:flex;flex-direction:column;min-height:0;flex:1}
body.webview-mode .side-col{min-height:0}
body.webview-mode .side-block{flex:1;min-height:0;display:flex;flex-direction:column;
  background:none;box-shadow:none;padding:0}
body.webview-mode .side-block h3,body.webview-mode .transcript-col h3{margin:0 0 8px}
/* плавающее окно — десктопный приём (мышь, drag за заголовок); в webview
   своя раскладка на весь экран (см. .mobile-tabbar), там position:fixed
   панель просто перекрывала бы всё поверх — кнопку прячем, чтобы не завести
   пользователя в состояние, из которого не выбраться на маленьком экране */
body.webview-mode #btn-speakers-float{display:none}
body.webview-mode #speakers-list,body.webview-mode #reco-list{
  flex:1;min-height:0;max-height:none;overflow-y:auto;padding:4px 8px;margin:0 -8px;
  display:flex;flex-direction:column;gap:10px}
body.webview-mode .speaker-chip{background:var(--card-bg);box-shadow:var(--card-shadow);
  border-left:3px solid var(--spk-color,var(--border));border-radius:8px;padding:10px 12px;
  margin-bottom:0;font-size:16px;cursor:default}
body.webview-mode .speaker-chip:hover{background:var(--card-bg)}
body.webview-mode .spk-icon{display:none}
body.webview-mode .reco-item{background:var(--card-bg);box-shadow:var(--card-shadow);
  border-radius:8px;margin-bottom:0;font-size:16px}
body.webview-mode #live-panel.panel-flex{flex-direction:column;flex:1;min-height:0;height:auto}
/* Отрицательные margin выносят таббар к физическим краям экрана, гася
   паддинги #tab-meeting.active/#live-panel.panel-flex; padding-bottom
   учитывает safe-area (жест/чёлка снизу). */
body.webview-mode .mobile-tabbar{display:flex;background:var(--card-bg);
  border-top:1px solid var(--border);border-radius:0;gap:6px;margin:10px -18px 0 -18px;flex-shrink:0;
  padding:6px 6px calc(6px + env(safe-area-inset-bottom, 0px)) 6px}
.mt-btn{flex:1;display:flex;align-items:center;justify-content:center;padding:9px;border-radius:8px;background:none;color:var(--text-muted)}
.mt-btn svg{width:22px;height:22px}
.mt-btn.active{background:var(--hover);color:var(--accent2)}
/* Видимость .side-col/.transcript-col управляется напрямую из JS
   (applyLiveVisibility()) через style.display, не CSS-классами — единый
   источник истины вместо гонки между вкладкой и режимом. */
