:root{
  --bg:#faf9f7; --surface:#fff; --surface2:#f2f0ec; --line:#e2ded6; --line2:#cfcabf;
  --txt:#1f1e1c; --dim:#6b6862; --muted:#93908a;
  --accent:#3f6cd6; --accent-bg:#e8eefc;
  --ok:#2f7d4f; --ok-bg:#e6f3ea; --warn:#9a6300; --warn-bg:#fdf0d9; --bad:#a83232; --bad-bg:#fbeaea;
  --ig:#c4426e; --tg:#2b7fc4; --fv:#b06d14;
  --r:10px;

  /* Настраиваемое из «Внешнего вида». Значения по умолчанию — то, как
     планировщик выглядел до появления настроек: сбросила и вернулась сюда.
     Всё остальное считается от этих величин, чтобы шкала не расползалась. */
  --page-w:1700px;      /* ширина содержимого страницы */
  --day-h:150px;        /* минимальная высота дня в календаре */
  --card-w:150px;       /* минимальная ширина карточки банка */
  --fs-big:22px;        /* крупный кегль: цифры, заголовки, месяц */
  --fs-sm:12.5px;       /* второстепенный: подписи, поля, плашки */
  --chip-h:50px;        /* высота плашки с контентом */
  --chip-h-empty:50px;  /* и высота пустого слота — они независимы */
  --chip-thumb:40px;    /* сторона обложки внутри плашки, 0 — без обложки */
  --chip-radius:8px;    /* скругление плашки справа */
  --chip-radius-l:0px;  /* и слева: 0 — прямой край под цветную полосу */
  --chip-border:1px;    /* рамка плашки, 0 — без неё */
  --chip-tint:20%;      /* насыщенность подложки занятой плашки */
  --chip-align:flex-start;  /* прижимать текст к верху или центрировать */
}
/* Палитра типов: разведённые тона средней насыщенности. Класс вешается
   по названию цвета, а не по названию типа — так свой тип получает цвет
   выбором из списка, а не правкой стилей. Плашка красится этим цветом,
   фон — им же, разбавленным поверхностью, поэтому в тёмной теме
   подложка темнеет сама. */
.tyc-rose       {--c:#c8506f}  /* розовый   — по умолчанию у Reels */
.tyc-violet     {--c:#9463c2}  /* сиреневый — Stories */
.tyc-indigo     {--c:#5a72c4}  /* индиго    — карусель */
.tyc-azure      {--c:#3387ab}  /* лазурный  — бытовое фото */
.tyc-teal       {--c:#2f8d7e}  /* бирюза    — голосовое */
.tyc-green      {--c:#5d9350}  /* зелёный   — кружок */
.tyc-olive      {--c:#8d9440}  /* оливковый — видео */
.tyc-terracotta {--c:#c56142}  /* терракота — NSFW */
.tyc-amber      {--c:#b5822f}  /* янтарный  — free-лента */
.tyc-plum       {--c:#a4507f}  /* слива     — свободный */
.tyc-steel      {--c:#5f7183}  /* стальной  — свободный, он же запасной */
.tyc-sand       {--c:#a08356}  /* песочный  — свободный */
/* Тёмные значения нужны в двух случаях: системная тёмная тема при выборе
   «как в системе» и принудительно выбранная тёмная. Поэтому каждый набор
   идёт дважды. Условие html:not([data-theme="light"]) гасит системную тему,
   когда она вручную переключена на светлую. */
@media (prefers-color-scheme: dark){
  /* В тёмной теме те же тона, но светлее — иначе тонут в фоне. */
  html:not([data-theme="light"]) .tyc-rose{--c:#e4839c} html:not([data-theme="light"]) .tyc-violet{--c:#b795e0}
  html:not([data-theme="light"]) .tyc-indigo{--c:#8fa2e6} html:not([data-theme="light"]) .tyc-azure{--c:#63b3d4}
  html:not([data-theme="light"]) .tyc-teal{--c:#5cbdad} html:not([data-theme="light"]) .tyc-green{--c:#8cbf7e}
  html:not([data-theme="light"]) .tyc-olive{--c:#bcc472} html:not([data-theme="light"]) .tyc-terracotta{--c:#e6906f}
  html:not([data-theme="light"]) .tyc-amber{--c:#dcae5f} html:not([data-theme="light"]) .tyc-plum{--c:#d489b4}
  html:not([data-theme="light"]) .tyc-steel{--c:#93a6b8} html:not([data-theme="light"]) .tyc-sand{--c:#cbb089}
}
html[data-theme="dark"] .tyc-rose{--c:#e4839c} html[data-theme="dark"] .tyc-violet{--c:#b795e0}
html[data-theme="dark"] .tyc-indigo{--c:#8fa2e6} html[data-theme="dark"] .tyc-azure{--c:#63b3d4}
html[data-theme="dark"] .tyc-teal{--c:#5cbdad} html[data-theme="dark"] .tyc-green{--c:#8cbf7e}
html[data-theme="dark"] .tyc-olive{--c:#bcc472} html[data-theme="dark"] .tyc-terracotta{--c:#e6906f}
html[data-theme="dark"] .tyc-amber{--c:#dcae5f} html[data-theme="dark"] .tyc-plum{--c:#d489b4}
html[data-theme="dark"] .tyc-steel{--c:#93a6b8} html[data-theme="dark"] .tyc-sand{--c:#cbb089}

html[data-theme="dark"]{
  --bg:#141416; --surface:#1c1c1f; --surface2:#232327; --line:#2e2e33; --line2:#3d3d44;
  --txt:#eceae6; --dim:#a3a09a; --muted:#75726d;
  --accent:#7ea2f0; --accent-bg:#1d2740;
  --ok:#6bc98d; --ok-bg:#16281d; --warn:#e0a94a; --warn-bg:#2b2213; --bad:#e97b7b; --bad-bg:#2c1919;
  --ig:#e8749b; --tg:#5fb0e8; --fv:#dd9c3c;
}
@media (prefers-color-scheme: dark){
  html:not([data-theme="light"]){
    --bg:#141416; --surface:#1c1c1f; --surface2:#232327; --line:#2e2e33; --line2:#3d3d44;
    --txt:#eceae6; --dim:#a3a09a; --muted:#75726d;
    --accent:#7ea2f0; --accent-bg:#1d2740;
    --ok:#6bc98d; --ok-bg:#16281d; --warn:#e0a94a; --warn-bg:#2b2213; --bad:#e97b7b; --bad-bg:#2c1919;
    --ig:#e8749b; --tg:#5fb0e8; --fv:#dd9c3c;
  }
}
*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{background:var(--bg);color:var(--txt);font:calc(var(--fs-big) * .682)/1.5 -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Inter,sans-serif;-webkit-font-smoothing:antialiased}
button{font:inherit;cursor:pointer;border:1px solid var(--line2);background:var(--surface);color:var(--txt);border-radius:var(--r);padding:7px 13px;transition:background .12s,border-color .12s}
button:hover{background:var(--surface2)}
button.primary{background:var(--accent);border-color:var(--accent);color:#fff}
button.primary:hover{filter:brightness(1.08)}
button.ghost{border-color:transparent;background:transparent}
button.ghost:hover{background:var(--surface2)}
button.sm{padding:4px 9px;font-size:calc(var(--fs-big) * .59)}
button.danger{color:var(--bad);border-color:var(--line)}
input,select,textarea{font:inherit;background:var(--surface);color:var(--txt);border:1px solid var(--line2);border-radius:var(--r);padding:8px 10px;width:100%}
.export-format{width:auto;padding:4px 28px 4px 9px;font-size:calc(var(--fs-big) * .59)}
input:focus,select:focus,textarea:focus{outline:2px solid var(--accent-bg);border-color:var(--accent)}
textarea{min-height:90px;resize:vertical}
label{display:block;font-size:var(--fs-sm);color:var(--dim);margin:12px 0 4px}
a{color:var(--accent)}
.hide{display:none!important}
.row{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.spacer{flex:1}
.dim{color:var(--dim)} .muted{color:var(--muted)}
.ok{color:var(--ok)} .warn{color:var(--warn)} .bad{color:var(--bad)}

/* Одинаковая панель действий в карточке банка и в занятом слоте календаря.
   Главное действие и публикация не смешиваются с компактными выгрузками. */
.item-actions{display:grid;gap:10px;margin-top:16px}
.item-actions-main{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.item-actions-main button{min-height:38px;padding-left:10px;padding-right:10px;white-space:nowrap}
.item-actions-secondary{display:flex;align-items:center;gap:6px;flex-wrap:wrap;padding-top:10px;border-top:1px solid var(--line)}
.item-actions-secondary button{padding-left:5px;padding-right:5px;white-space:nowrap}
.item-actions-secondary .export-format{width:72px;padding-left:7px;padding-right:22px;white-space:nowrap}

header{position:sticky;top:0;z-index:40;background:var(--surface);border-bottom:1px solid var(--line);padding:10px 18px;display:flex;align-items:center;gap:16px;flex-wrap:wrap}
header h1{font-size:calc(var(--fs-big) * .682);font-weight:600;margin:0;letter-spacing:-.2px;white-space:nowrap}
/* Все вкладки собраны в одну прямоугольную панель: общая рамка снаружи,
   тонкие разделители внутри. Цвет появляется только у активной вкладки. */
nav{display:flex;gap:0;flex-wrap:nowrap;align-items:stretch;max-width:100%;overflow-x:auto;
  border:1px solid var(--line2);border-radius:0;background:var(--surface);scrollbar-width:thin}
nav button{--nav-c:#8a929b;flex:none;border:0;border-right:1px solid var(--line2);
  background:var(--surface);color:var(--txt);padding:6px 11px;border-radius:0;
  font-size:calc(var(--fs-big) * .64);cursor:grab;box-shadow:none;
  transition:background .12s,opacity .12s}
nav button:last-child{border-right:0}
nav button:hover{background:var(--surface2)}
nav button:active{cursor:grabbing}
nav button.on{background:color-mix(in srgb,var(--nav-c) 27%,var(--surface));
  color:var(--txt);font-weight:600}
nav button.dragging{opacity:.38}
nav button.navdrop{outline:2px solid color-mix(in srgb,var(--nav-c) 60%,var(--accent));outline-offset:2px}
nav button[data-v="cal"]{--nav-c:#7395c1}
nav button[data-v="todo"]{--nav-c:#c29a59}
nav button[data-v="bank"]{--nav-c:#6f9b7d}
nav button[data-v="edit"]{--nav-c:#967fb2}
nav button[data-v="blanks"]{--nav-c:#b77e91}
nav button[data-v="refs"]{--nav-c:#659997}
nav button[data-v="gen"]{--nav-c:#a26f9a}
nav button[data-v="stock"]{--nav-c:#a89066}
nav button[data-v="an"]{--nav-c:#7c88ad}
nav button[data-v="set"]{--nav-c:#858b92}
.hdrpill{font-size:var(--fs-sm);color:var(--dim);background:var(--surface2);padding:5px 11px;border-radius:99px;white-space:nowrap}

main{padding:18px;max-width:var(--page-w);margin:0 auto}
.card{background:var(--surface);border:1px solid var(--line);border-radius:14px;padding:16px}
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:10px;margin-bottom:16px}
.kpi{background:var(--surface);border:1px solid var(--line);border-radius:12px;padding:12px 14px}
.kpi .l{font-size:var(--fs-sm);color:var(--dim)}
.kpi .v{font-size:var(--fs-big);font-weight:600;margin-top:2px;letter-spacing:-.5px}
.kpi.warn{background:var(--warn-bg);border-color:transparent}
.kpi.bad{background:var(--bad-bg);border-color:transparent}

.toolbar{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:14px}
.month{font-size:calc(var(--fs-big) * .773);font-weight:600;min-width:150px;text-align:center;letter-spacing:-.3px}

/* Конструктор промптов. Каталог намеренно отдельный от признаков кадров:
   здесь признаки — части фразы, а не аналитическая разметка банка. */
.gen-head{display:flex;gap:24px;align-items:flex-end;justify-content:space-between;margin-bottom:14px}
.gen-eyebrow{margin-bottom:5px;color:var(--accent);font-size:10px;font-weight:750;letter-spacing:1.1px}
.gen-head h2{margin:0 0 4px;font-size:calc(var(--fs-big) * .9);letter-spacing:-.4px}
.gen-intro{max-width:680px;font-size:var(--fs-sm)}
.gen-controls{display:flex;gap:8px;align-items:flex-end;flex-wrap:wrap;justify-content:flex-end}
.gen-controls label{margin:0;width:112px;font-size:calc(var(--fs-sm) * .92)}
.gen-controls input{margin-top:4px;padding:6px 8px}
.gen-controls button{margin-bottom:1px;white-space:nowrap}
.gen-work{display:block}
.gen-builder{width:100%}
.gen-title-row{margin-bottom:12px}
.gen-title-row input{width:230px;padding:6px 8px}
/* Карточка признака собрана по рецепту плашки календаря: корешок 4px в цвет
   режима, подложка в те же --chip-tint процентов, рамка в 32%, кегли от
   --fs-sm с тем же отношением 1.25 между строками. Правишь размер шрифта
   в «Внешнем виде» — конструктор едет следом сам, как и календарь. */
.gen-traits{display:grid;grid-template-columns:repeat(auto-fill,minmax(232px,1fr));gap:6px;align-items:start}
.gen-trait{--gt-name:calc(var(--fs-sm) * 1.02); --gt-sub:calc(var(--gt-name) / 1.25);
  min-width:0;display:flex;flex-direction:column;gap:5px;padding:5px 8px;
  border-radius:0 8px 8px 0;
  border:1px solid color-mix(in srgb, var(--gc,var(--line2)) 32%, var(--surface));
  border-left:4px solid var(--gc,var(--line2));
  background:color-mix(in srgb, var(--gc,var(--line2)) var(--gen-tint), var(--surface));
  transition:background .15s ease,transform .12s ease,filter .15s ease,opacity .15s ease}
.gen-trait:hover{background:color-mix(in srgb, var(--gc,var(--line2)) calc(var(--gen-tint) + 12%), var(--surface));
  transform:translateX(1px)}
/* Выключённый — та же обесцвеченная карточка, что у отфильтрованной плашки. */
.gen-trait.gen-off{filter:grayscale(1);opacity:.42}
.gen-trait.gen-off:hover{filter:grayscale(.4);opacity:.85}
/* Высота у выключенного та же: строка выбора остаётся на месте и только
   перестаёт нажиматься. Иначе сетка прыгает при каждом щелчке. */
.gen-trait.gen-off .gen-choice{pointer-events:none}
.gen-trait.dragging{opacity:.32}
.gen-trait.gen-drop{border-color:var(--accent);box-shadow:0 0 0 2px color-mix(in srgb,var(--accent) 18%,transparent)}
.gen-trait-head{display:flex;align-items:center;gap:5px;min-width:0}
/* Верхний регистр у названия — не украшение: признаки перебирают глазами,
   и заглавные держат строку узнаваемой в сетке из полутора десятков карточек.
   Кегль при этом календарный, от --fs-sm. */
.gen-trait-name{flex:1;min-width:48px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:var(--gt-name);font-weight:750;letter-spacing:.25px;text-transform:uppercase;color:var(--txt)}
.gen-trait-role{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:center;gap:7px;margin:8px 0 0;color:var(--dim);font-size:10px;text-transform:uppercase;letter-spacing:.35px}
.gen-trait-role select{min-width:0;padding:5px 22px 5px 7px;font-size:11px;text-transform:none;letter-spacing:0}
.gen-drag{border:0;background:transparent;color:var(--muted);padding:1px 3px;font-size:15px;line-height:1;cursor:grab}
.gen-drag:active{cursor:grabbing}
/* Ряд значков режима. Невыбранный обесцвечен — приём тот же, что у плашек
   под фильтром типа, и работает на градиенте без правки самого рисунка. */
.gen-modes{display:flex;gap:1px;flex:0 0 auto}
.gen-mode{display:grid;place-items:center;width:20px;height:22px;padding:0;border:0;border-radius:6px;
  background:transparent;cursor:pointer;transition:background .12s,transform .1s}
.gen-mode:hover{background:color-mix(in srgb,var(--surface) 70%,transparent)}
.gen-mode:active{transform:translateY(1px)}
.gen-mode svg{width:18px;height:18px;display:block}
.gen-mode:not(.on) svg{filter:grayscale(1) opacity(.4)}
.gen-mode.on{background:color-mix(in srgb,var(--surface) 85%,transparent);box-shadow:0 1px 2px rgba(0,0,0,.12)}
/* Квадратик включения — тот же, что отметка о публикации в плашке. */
.gen-on{width:14px;height:14px;flex:0 0 auto;align-self:center;margin-left:2px;padding:0;
  border:1.25px solid color-mix(in srgb,var(--gc,var(--line2)) 45%,var(--surface));
  border-radius:4px;background:var(--surface);color:transparent;
  font-size:9px;line-height:1;display:flex;align-items:center;justify-content:center;cursor:pointer;
  transition:background .15s ease,border-color .15s ease,color .15s ease}
.gen-on:hover{border-color:var(--gc,var(--line2));color:color-mix(in srgb,var(--gc,var(--line2)) 50%,var(--surface))}
.gen-trait:not(.gen-off) .gen-on{background:var(--gc,var(--line2));border-color:var(--gc,var(--line2));color:#fff}
/* Обе строки выбора одной высоты, иначе карточки разных режимов стоят
   в сетке вразнобой на пиксель. */
.gen-choice{min-width:0}
.gen-choice select,.gen-some{width:100%;height:24px;padding:0 6px;font-size:var(--gt-sub);
  border:1px solid color-mix(in srgb,var(--gc,var(--line2)) 30%,var(--surface));border-radius:6px;
  background:var(--surface)}
.gen-choice select{font-weight:600}
.gen-choice .dim{font-size:var(--gt-sub)}
/* Нижняя строка: число вариантов слева, действия справа. В шапку они
   больше не влезают, а прятать их совсем нельзя. */
.gen-values{min-width:0;width:100%;border:0}
.gen-values>summary{display:flex;align-items:center;gap:6px;color:var(--dim);font-size:var(--gt-sub);
  font-variant-numeric:tabular-nums}
.gen-values>summary::-webkit-details-marker{display:none}
.gen-values>summary::marker{content:''}
.gen-trait-actions{display:flex;gap:0;margin-left:auto;
  color:color-mix(in srgb,var(--txt) 45%,transparent)}
.gen-trait-actions button{border:0;background:transparent;padding:0 2px;color:inherit;font-size:12px}
.gen-trait-actions button:hover{color:var(--txt)}
.gen-some{display:flex;align-items:center;cursor:pointer;color:var(--dim)}
.gen-some[open]{height:auto;display:block;padding:6px 8px}
.gen-some summary,.gen-rules summary{cursor:pointer;color:var(--dim);font-size:var(--gt-sub)}
.gen-value-list{display:flex;flex-wrap:wrap;gap:5px;margin-top:7px}
.gen-values[open] .gen-value-list{display:grid;grid-template-columns:1fr}
.gen-value-chip{display:grid;grid-template-columns:minmax(0,1fr) 29px auto;align-items:center;gap:3px;width:100%;box-sizing:border-box;border:1px solid var(--line);background:var(--surface);border-radius:8px;padding:3px 6px 3px 7px;font-size:var(--fs-sm)}
.gen-value-input{min-width:0;width:100%;border:1px solid transparent;background:transparent;padding:3px 4px;color:var(--txt);font:inherit}
/* Рука визуально не смешивается с флажками выбора вариантов в верхней части
   карточки. Приглушённая — свободна, выделенная — занята этим вариантом. */
.gen-value-chip .gen-hands{display:grid;place-items:center;width:29px;height:26px;margin:0;padding:0;border:1px solid transparent;border-radius:7px;background:transparent;filter:grayscale(1);opacity:.32;font-size:16px;line-height:1;cursor:pointer}
.gen-value-chip .gen-hands:hover{background:var(--line);opacity:.65}
.gen-value-chip .gen-hands.on{border-color:color-mix(in srgb,var(--accent) 38%,var(--line));background:color-mix(in srgb,var(--accent) 12%,var(--surface));filter:none;opacity:1}
.gen-value-chip .gen-hands:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.gen-value-input:hover{border-color:var(--line2);background:var(--bg)}
.gen-value-input:focus{border-color:var(--accent);background:var(--bg);outline:0;box-shadow:0 0 0 2px color-mix(in srgb,var(--accent) 14%,transparent)}
.gen-value-chip button{border:0;background:transparent;padding:0 3px;color:var(--muted);font-size:11px}
.gen-add-value{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px;margin-top:8px}
.gen-add-value input{min-width:0;width:100%;padding:6px 8px}
.gen-add-value button{white-space:nowrap}
.gen-checks{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:5px;margin-top:7px}
.gen-checks label{display:flex;align-items:flex-start;gap:6px;margin:0;padding:5px 7px;border-radius:7px;background:var(--surface);color:var(--txt)}
.gen-checks input{width:auto;margin:3px 0 0}
.gen-empty{padding:26px 18px;text-align:center;border:1px dashed var(--line2);border-radius:12px;color:var(--dim)}
.gen-rules{margin-top:14px;border-top:1px solid var(--line);padding-top:11px}
.gen-rule-help{font-size:var(--fs-sm);margin:8px 0}
.gen-rule-help code{background:var(--surface2);padding:1px 4px;border-radius:4px}
.gen-rule-example{margin:8px 0 10px;padding:9px 11px;border:1px solid var(--line);border-radius:8px;background:var(--surface);white-space:pre-wrap;font:12px/1.55 ui-monospace,SFMono-Regular,Consolas,monospace}
.gen-rules textarea{min-height:100px;margin-bottom:7px}
.gen-visual-rules{display:grid;gap:8px;margin:10px 0}
.gen-rule-empty{padding:12px;border:1px dashed var(--line2);border-radius:9px;color:var(--dim);font-size:var(--fs-sm)}
/* Строка вместо карточки: тридцать восемь запретов раскладывались на три
   экрана, и до кнопок сборки приходилось долго мотать. Правило теперь живёт
   в одну строку, длинное перечисление сворачивается в «+N», целиком оно
   видно в подсказке и в редакторе. */
/* Группа на признак первого условия. Заголовки короткие, поэтому закрытый
   список запретов умещается в шесть строк вместо тридцати восьми. */
.gen-rule-group{border-radius:8px}
.gen-rule-group+.gen-rule-group{margin-top:2px}
.gen-rule-group>summary{display:flex;align-items:baseline;gap:6px;padding:4px 7px;border-radius:7px;
  cursor:pointer;font-size:var(--fs-sm)}
.gen-rule-group>summary:hover{background:var(--surface2)}
.gen-rule-group>summary b{text-transform:uppercase;font-size:10px;letter-spacing:.35px}
.gen-rule-group>summary span{color:var(--muted);font-size:11px}
.gen-rule-group[open]>summary{color:var(--accent)}
.gen-rule-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;
  padding:3px 7px 3px 20px;border-radius:7px;cursor:pointer}
/* Считаем среди строк, а не среди детей: первым ребёнком группы стоит её
   заголовок, и полоски сползали на строку. */
.gen-rule-row:nth-of-type(odd){background:var(--surface)}
.gen-rule-row:hover{background:var(--surface2)}
.gen-rule-row.is-off{opacity:.5}
.gen-rule-state{flex:none;color:var(--dim);font-size:9.5px;font-weight:750;letter-spacing:.5px;text-transform:uppercase}
.gen-rule-row.is-off .gen-rule-state{color:var(--dim)}
/* Одна строка без переносов: ширина колонки задана сеткой, лишнее уходит
   в многоточие — иначе одно правило на двадцать вариантов растягивало ряд. */
.gen-rule-parts{display:flex;align-items:center;gap:6px;min-width:0;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;font-size:var(--fs-sm)}
.gen-rule-part{display:inline-flex;align-items:baseline;gap:5px;min-width:0}
.gen-rule-part b{text-transform:uppercase;font-size:9.5px;letter-spacing:.3px;color:var(--muted)}
.gen-rule-part>span{color:var(--txt);overflow:hidden;text-overflow:ellipsis}
.gen-rule-part i{flex:none;padding:0 4px;border-radius:5px;background:var(--line);
  color:var(--dim);font-size:10px;font-style:normal;font-weight:700}
.gen-rule-plus{flex:none;color:var(--muted);font-weight:700}
/* Значки проявляются на строке, к которой тянешься: постоянный ряд из трёх
   кнопок на каждом правиле сам по себе делал список пёстрым. */
.gen-rule-card-actions{display:flex;gap:2px;justify-content:flex-end;opacity:0;transition:opacity .12s}
.gen-rule-row:hover .gen-rule-card-actions,
.gen-rule-row:focus-within .gen-rule-card-actions{opacity:1}
.gen-rule-card-actions button{width:22px;height:20px;padding:0;font-size:12px;line-height:1}
.gen-rules-count{color:var(--muted);font-weight:400}
.gen-rule-editor{margin:10px 0;padding:12px;border:1px solid color-mix(in srgb,var(--accent) 48%,var(--line));border-radius:11px;background:color-mix(in srgb,var(--accent) 4%,var(--bg))}
.gen-rule-editor-title{margin-bottom:10px;font-weight:700}
.gen-rule-conditions{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:9px;align-items:start}
.gen-rule-condition{min-width:0;padding:10px;border:1px solid var(--line);border-radius:9px;background:var(--bg)}
.gen-rule-condition>label{margin:0 0 8px;font-size:10px;color:var(--dim);text-transform:uppercase;letter-spacing:.35px}
.gen-rule-condition>label span{display:block;margin-bottom:3px}
.gen-rule-condition select{width:100%}
.gen-rule-condition details summary{cursor:pointer;color:var(--dim);font-size:11px}
.gen-rule-values{display:grid;gap:2px;margin-top:6px;max-height:168px;overflow:auto}
.gen-rule-values label{display:flex;align-items:flex-start;gap:6px;margin:0;padding:3px 6px;border-radius:6px;background:var(--surface);color:var(--txt);font-size:var(--fs-sm);line-height:1.3}
.gen-rule-values input{width:auto;margin:3px 0 0}
.gen-rule-and{display:none}
.gen-rule-condition>[data-rule-remove]{margin-top:8px}
.gen-rule-editor-actions{display:flex;align-items:center;gap:7px;margin-top:10px;padding-top:9px;border-top:1px solid var(--line)}
.gen-rule-advanced{margin-top:10px;padding-top:9px;border-top:1px solid var(--line)}
.gen-rule-advanced>summary{cursor:pointer;color:var(--dim);font-size:11px}
.gen-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:14px;padding-top:12px;border-top:1px solid var(--line)}
.gen-output{position:static;width:100%;margin-top:14px}
.gen-status{font-size:var(--fs-sm);margin:10px 0}
.gen-preview{max-height:430px;overflow:auto;border:1px solid var(--line);border-radius:10px;margin-bottom:10px}
.gen-preview-row{padding:8px 10px;border-bottom:1px solid var(--line);font-size:var(--fs-sm)}
.gen-preview-row:last-child{border-bottom:0}
.gen-preview-row b{color:var(--dim);font-weight:500}
.gen-result{min-height:280px;line-height:1.55;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:13px}
.gen-result-rich{height:280px;min-height:280px;overflow:auto;white-space:pre-wrap;border:1px solid var(--line);border-radius:10px;padding:10px 11px;background:var(--bg);color:var(--txt);box-sizing:border-box;user-select:text}
.gen-rich-prompt{padding:0 0 13px;margin:0 0 13px;border-bottom:1px dashed var(--line2)}
.gen-rich-prompt:last-child{padding-bottom:0;margin-bottom:0;border-bottom:0}
.gen-source{padding:1px 3px;border-radius:4px;box-decoration-break:clone;-webkit-box-decoration-break:clone}
.gen-source-0{background:#ffe0e6;color:#7f2038}.gen-source-1{background:#e4e0ff;color:#46318a}
.gen-source-2{background:#d9f2ff;color:#175a78}.gen-source-3{background:#ddf4df;color:#23642b}
.gen-source-4{background:#fff0c7;color:#765400}.gen-source-5{background:#f8dcff;color:#71307e}
.gen-source-6{background:#d8f3ed;color:#17685a}.gen-source-7{background:#ffe3ce;color:#814014}

.dow{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:6px;margin-bottom:6px}
.dow div{font-size:calc(var(--fs-sm) * .92);color:var(--muted);padding-left:4px;text-transform:uppercase;letter-spacing:.5px}
.grid{display:block}
/* Внутреннего окна у календаря нет: недели продолжают страницу вниз и
   прокручиваются обычным колесом вместе с ней. */
.calwrap{display:block}
.calweek{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:6px;margin-bottom:6px}
.day{background:var(--surface);border:1px solid var(--line);border-radius:12px;min-height:var(--day-h);padding:6px;display:flex;flex-direction:column;gap:5px;
  transition:opacity .15s ease}
.day.out{opacity:.4}
.day.past-day:not(.out){opacity:.62}
.day.past-day:not(.out):hover{opacity:.82}
/* Сегодня выделено всей плоскостью ячейки: чёрный фон без отдельной рамки.
   Плашки контента сохраняют собственные цвета поверх него. */
.day.today{background:#111;border-color:transparent;box-shadow:none}

/* Прямой потомок, а не любой вложенный: класс `n` носит и строка плашки
   (площадка + тип). Без `>` кружок номера дня доставался первому элементу
   этой строки — то есть значку площадки, и на сегодняшнем дне все значки
   оказывались в сиреневых кружках. */
.day>.n{font-size:11.5px;color:var(--muted);padding:0 2px 2px;display:flex;
  justify-content:space-between;align-items:center;gap:4px}
.day>.n span:first-child{white-space:nowrap}
.day.today>.n span:first-child{color:#fff;font-weight:600;white-space:nowrap}
.day.over{border-color:var(--accent);background:var(--accent-bg)}
/* Каждая плашка обведена — иначе в плотном дне они слипаются в полосу,
   и особенно это заметно у бледных пустых. Левый край прямой: цветная
   полоса читается как корешок, а не как деталь скруглённой карточки. */
/* Высота у всех плашек одна — по обложке: 40 px картинки плюс отступы.
   Пустая без обложки тянется до той же высоты, иначе строки в дне скачут.
   Текст прижат к верху, вровень с верхним краем превью. */
.chip{display:flex;align-items:var(--chip-align);gap:7px;font-size:calc(var(--fs-sm) * .92);padding:5px 8px;cursor:pointer;
  min-height:var(--chip-h);overflow:hidden;white-space:nowrap;
  border-radius:var(--chip-radius-l) var(--chip-radius) var(--chip-radius) var(--chip-radius-l);
  border:var(--chip-border) solid var(--line);
  border-left:4px solid var(--c,var(--line2));
  border-color:color-mix(in srgb, var(--c,var(--line2)) 32%, var(--surface));
  border-left-color:var(--c,var(--line2));
  background:color-mix(in srgb, var(--c,var(--line2)) var(--chip-tint), var(--surface));
  transition:background .15s ease, transform .12s ease}
/* На чёрном фоне сегодняшнего дня плашки уже отделены контрастом, поэтому
   дополнительную тёмную обводку убираем. Цветной корешок типа остаётся. */
.day.today .chip{border-width:0 0 0 4px;border-style:solid;
  border-left-color:var(--c,var(--line2))}
.chip:hover{background:color-mix(in srgb, var(--c,var(--line2)) 32%, var(--surface));transform:translateX(1px)}
.chip:active{transform:translateX(1px) scale(.99)}
/* Пустому слоту подложка почти не нужна, а вот граница нужна:
   бледные плашки без неё сливаются в один серый блок. */
.chip.noitem{min-height:var(--chip-h-empty)}
.chip.empty{background:color-mix(in srgb, var(--c,var(--line2)) 6%, var(--surface));
  border-color:color-mix(in srgb, var(--c,var(--line2)) 22%, var(--surface));
  border-left-color:color-mix(in srgb, var(--c,var(--line2)) 45%, var(--surface))}
.chip.empty:hover{background:color-mix(in srgb, var(--c,var(--line2)) 15%, var(--surface))}
.chip.empty .t{font-weight:500;color:var(--dim)}
/* Две строки плашки различаются кеглем: название типа главное, время —
   уточнение. Считаем от одного значения, чтобы отношение не разъезжалось
   при правке размера шрифта в настройках вида.

   Отношение 1.25, а не типографские полтора: на полутора время выходило
   в девять пикселей, и владелец его попросту не читала. Разница в кегле
   нужна для порядка чтения, а не любой ценой. */
.chip{--chip-name:calc(var(--fs-sm) * 1.02); --chip-time:calc(var(--chip-name) / 1.25)}
/* Блок строк по центру обложки: строки короче превью, и прижатые кверху
   они висели в воздухе. Выравнивание самой обложки остаётся за настройкой. */
/* Зазор между строками заметный: в один пиксель название типа и время
   выглядели одним слипшимся блоком, хотя это разные сведения. */
.chip .ci{flex:1;min-width:0;align-self:center;display:flex;flex-direction:column;gap:4px;line-height:1.25}
/* Строка времени не переносится: в узкой колонке перенос ломал плашки
   на три этажа разной высоты. Не влезло — обрезаем по краю. */
.chip .tl{display:flex;align-items:baseline;gap:5px;min-width:0;overflow:hidden;
  font-size:var(--chip-time)}
.chip .tl>*{flex:0 0 auto}
/* Оба пояса одного кегля: разный размер делал время аудитории похожим
   на сноску, хотя это второе полноценное время. Своё жирным — по нему
   живёт владелец. Разделены чертой, а не просто пробелом: без неё четыре
   группы цифр и букв сливались в одну строку. */
.chip .t{color:var(--txt);font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:-.1px}
.chip .t2{color:var(--muted);font-variant-numeric:tabular-nums;letter-spacing:-.1px}
.chip .sep{color:var(--line2);opacity:.7}
/* Строка «площадка + тип» — флексом, а не строчными элементами: у значка
   и текста разные базовые линии, и подгонка через vertical-align давала
   заметный перекос. Обрезается многоточием только название типа.

   justify-content задан явно: класс `n` носит и номер дня (`.day .n`),
   а он раскидывает своё содержимое по краям. Плашка лежит внутри дня,
   и без этой строки значок с типом разъезжались в разные стороны. */
.chip .n{display:flex;justify-content:flex-start;align-items:center;gap:5px;
  min-width:0;flex:none;padding:0;color:var(--dim);font-size:var(--chip-name)}
/* Площадка значком и своим цветом, тип поста за ней приглушённо: в одном дне
   стоят Reels, Stories и телеграмные посты, и первым читается «куда», а «чем»
   уже вторым. Значок вместо слова — иначе «Instagram Фото-карусель» не влезает
   в узкую плашку и обрезается как раз тип. Цвет плашки говорит про тип,
   поэтому цветом здесь помечена именно площадка. */
/* Значок в em от строки типа: правишь кегль — знак идёт следом сам. */
.chip .pf{display:flex;align-items:center;flex:0 0 auto}
.chip .pf :is(svg,.pfimg){width:1.16em;height:1.16em;display:block;object-fit:contain}
/* Своя площадка значка не имеет — монограмма из первой буквы. Обводкой,
   а не заливкой: заливка currentColor не даёт покрасить саму букву. */
/* Размер в em от собственного кегля, поэтому 1.61 = те же 1.16em строки. */
.chip .pfm{display:grid;place-items:center;font-style:normal;font-weight:800;
  width:1.61em;height:1.61em;font-size:.72em;line-height:1;
  border:1.5px solid currentColor;border-radius:3.5px}
/* Обрезается тип, а не площадка: «куда» важнее «чем». */
.chip .tn{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted)}
/* Обложка поста прямо в ячейке — видно занятое время, не открывая слот. */
.chip .cth{width:var(--chip-thumb);height:var(--chip-thumb);border-radius:5px;object-fit:cover;flex:0 0 auto;background:var(--surface2)}
/* Слот без контента: рамка вместо обложки. Место занимает то же, поэтому
   надписи в пустых и заполненных плашках начинаются с одной вертикали —
   иначе колонка дня читается лесенкой. */
.chip .cth-none{box-sizing:border-box;background:transparent;
  border:1px solid color-mix(in srgb, var(--c,var(--line2)) 55%, var(--surface))}
/* Выбран один тип — остальные обесцвечиваются. Не прячем: важно видеть,
   чем день уже занят и где ещё пусто. Наведение приподнимает обратно,
   чтобы приглушённое всё равно можно было рассмотреть и открыть. */
.chip.mono{filter:grayscale(1);opacity:.42}
.chip.mono:hover{opacity:.85;filter:grayscale(.4)}

/* Подсветка цели, когда один пост тащат на другой для обмена. */
.chip.swap{outline:2px solid var(--accent);outline-offset:-1px;background:var(--accent-bg)}
/* Квадратик отметки: пустой — пока не выложено, залитый — выложено. */
/* Галочка держится по центру плашки, а не уезжает наверх вместе с текстом. */
/* Галочка мелкая и по центру высоты плашки: это отметка о факте, а не
   действие — нажимают её редко, а места она занимала как кнопка.
   align-self перебивает общее выравнивание плашки из настроек вида. */
.chip .ck{width:14px;height:14px;flex:0 0 auto;align-self:center;margin-left:1px;padding:0;
  border:1.25px solid color-mix(in srgb, var(--c,var(--line2)) 45%, var(--surface));
  border-radius:4px;background:var(--surface);color:transparent;
  font-size:9px;line-height:1;display:flex;align-items:center;justify-content:center;
  transition:background .15s ease, border-color .15s ease, color .15s ease}
.chip .ck:hover{border-color:var(--c,var(--line2));background:var(--surface);
  color:color-mix(in srgb, var(--c,var(--line2)) 50%, var(--surface))}

/* Выложенное от неопубликованного отличается ровно одним — залитой галочкой.
   Сама плашка не меняется: цвет типа и так занят делом, а второй сигнал
   поверх него превращал календарь в лоскутное одеяло. */
.chip.done .ck,.chip.done .ck:hover{background:var(--c,var(--line2));
  border-color:var(--c,var(--line2));color:#fff}
/* Пропущенный день: тот же цвет типа, только бледнее — это след, а не ошибка. */
.chip.missed{background:color-mix(in srgb, var(--c,var(--line2)) 8%, var(--surface));
  border-color:color-mix(in srgb, var(--c,var(--line2)) 22%, var(--surface));
  border-left-color:color-mix(in srgb, var(--c,var(--line2)) 50%, var(--surface));
  opacity:.75}
.chip.missed .t{color:var(--dim);font-weight:500}
.chip.missed:hover{opacity:1;background:color-mix(in srgb, var(--c,var(--line2)) 16%, var(--surface))}
.chip.err{background:var(--bad-bg);border-color:var(--bad)}
.chip.err .t{color:var(--bad)}

.agenda{display:none;flex-direction:column;gap:8px}
.datestrip{display:flex;gap:6px;overflow-x:auto;padding-bottom:6px;margin-bottom:6px}
.datestrip button{min-width:52px;padding:7px 6px;text-align:center;line-height:1.2;font-size:12px}
.datestrip button.on{background:var(--accent);border-color:var(--accent);color:#fff}
.arow{display:flex;align-items:center;gap:11px;background:var(--surface);border:1px solid var(--line);border-radius:12px;padding:9px 11px;cursor:pointer}
.arow:hover{border-color:var(--line2)}
.arow .th{width:46px;height:46px;border-radius:8px;background:var(--surface2);border-left:4px solid var(--c,var(--line2));object-fit:cover;flex:0 0 auto;display:flex;align-items:center;justify-content:center;color:var(--muted);font-size:11px}
.arow .m{flex:1;min-width:0}
.arow .m b{display:block;font-size:14px;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.arow .m span{font-size:12px;color:var(--dim)}

/* Ежедневник: отдельный календарь, в котором содержимое дня видно сразу.
   Высоту не ограничиваем — длинный список должен оставаться читаемым,
   а не прятаться за «ещё N». */
.todoadd{display:grid;grid-template-columns:150px minmax(260px,1fr) auto;gap:12px;align-items:end;margin-bottom:10px}
.todoadd label{margin-top:0}
.todoadd textarea{min-height:68px;margin:0}
.todoadd button{margin-bottom:1px}
.todohint{font-size:var(--fs-sm);color:var(--dim);margin:0 2px 14px}
.tododow{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:6px;margin-bottom:6px}
.tododow div{font-size:calc(var(--fs-sm) * .92);color:var(--muted);padding-left:7px;text-transform:uppercase;letter-spacing:.5px}
.todogrid{display:block}
.todoweek{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:6px;margin-bottom:6px;align-items:stretch}
.tododay{background:var(--surface);border:1px solid var(--line);border-radius:12px;min-height:165px;padding:7px;display:flex;flex-direction:column;gap:5px}
.tododay.out{opacity:.48}
.tododay.past-day:not(.out){opacity:.62}
.tododay.past-day:not(.out):hover{opacity:.82}
.tododay.today{border-color:#111}
.tododay.today .todonum{background:#111;color:#fff;border-radius:99px;min-width:21px;height:21px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-weight:600}
.tododay.todoover{border-color:var(--accent);background:var(--accent-bg)}
.tododate{font-size:11.5px;color:var(--muted);padding:0 2px 2px;display:flex;align-items:center;gap:5px}
.todocount{margin-left:auto;font-size:10.5px;color:var(--muted)}
.todolist{display:flex;flex-direction:column;gap:4px}
.todotask{display:grid;grid-template-columns:18px 18px minmax(0,1fr) auto;gap:4px;align-items:start;padding:5px 5px 5px 4px;border:1px solid var(--line);border-radius:7px;background:var(--surface2);font-size:calc(var(--fs-sm) * .9);line-height:1.3;cursor:grab}
.todotask:active{cursor:grabbing}
.todotask.dragging{opacity:.38}
.todoidx{color:var(--muted);font-variant-numeric:tabular-nums}
.todock{width:17px;height:17px;padding:0;border-radius:5px;display:flex;align-items:center;justify-content:center;font-size:11px;line-height:1;color:transparent;background:var(--surface);border:1.5px solid var(--line2)}
.todock:hover{border-color:var(--accent);color:var(--muted)}
.todotask.done .todock,.todotask.done .todock:hover{background:var(--accent);border-color:var(--accent);color:#fff}
.todobody{min-width:0;overflow-wrap:anywhere;white-space:pre-wrap}
.todotask.done .todobody{text-decoration:line-through;color:var(--muted)}
.todoactions{display:flex;gap:1px;opacity:0;transition:opacity .12s}
.todotask:hover .todoactions,.todotask:focus-within .todoactions{opacity:1}
.todoactions button{border:none;background:transparent;padding:0 2px;color:var(--muted);font-size:12px;line-height:17px}
.todoactions button:hover{background:transparent;color:var(--txt)}
.todoempty{font-size:11.5px;color:var(--muted);padding:5px 3px}

textarea.need,input.need{border-color:var(--warn);background:var(--accent-bg)}

.capopt{border:1px solid var(--line);border-radius:9px;padding:8px 10px;margin-bottom:6px;font-size:13px;cursor:pointer;background:var(--surface);transition:.12s}
.capopt:hover{border-color:var(--accent);background:var(--accent-bg)}
.capopt.on{border-color:var(--accent);background:var(--accent-bg);font-weight:500}
/* Первый комментарий Threads под своим же постом: отступом и цветом видно,
   что это отдельная реплика, а не хвост подписи. */
.capopt .capreply{display:block;margin-top:6px;padding-left:9px;border-left:2px solid var(--line);
  color:var(--dim);font-weight:400;white-space:pre-wrap}

/* Лента Threads: тёмная, как у большинства, круглый аватар, ветка второй
   строкой. Нить между аватарами — та самая линия, которой площадка
   показывает, что комментарий принадлежит автору поста.

   Колонка шире телеграмной: на телефоне лента занимает всю ширину экрана,
   и в узком макете строки рвались раньше, чем в приложении. */
.drawer.tg-compose-open.wide-pv{width:min(1040px,96vw);
  grid-template-columns:minmax(340px,1fr) 470px}
.tg-preview-column.th-skin{background:#0a0a0b;color:#f3f3f5;border-left-color:#26262b}
.th-skin .tg-preview-label{color:#8b8d98}
.th-skin .tg-preview-note{color:#6f717c}
.th-skin .tgp-audit{background:#221d0c;border-color:#6b5a20;color:#e8d9a6}
.th-skin .tgp-audit.bad{background:#2a1414;border-color:#7a3030;color:#f0c9c9}
.thp-post{background:#0a0a0b;border:1px solid #26262b;border-radius:14px;padding:14px 15px;
  color:#f3f3f5}
.thp-row{display:grid;grid-template-columns:38px minmax(0,1fr);gap:10px;position:relative}
.thp-row+.thp-row{margin-top:12px}
.thp-side{display:flex;flex-direction:column;align-items:center}
.thp-ava{width:34px;height:34px;border-radius:50%;display:grid;place-items:center;flex:0 0 auto;
  background:linear-gradient(140deg,#4a4a55,#1a1a20);color:#fff;font-weight:700;font-size:14px;
  border:1px solid #33333b}
.thp-row:not(:last-child) .thp-side::after{content:'';flex:1;width:2px;margin-top:6px;
  background:#2c2c33;border-radius:2px}
.thp-head{display:flex;align-items:baseline;gap:8px;font-size:14px}
.thp-head time{color:#7d7f8a;font-size:12px}
.thp-text{margin-top:3px;font-size:15px;line-height:1.45;white-space:pre-wrap;overflow-wrap:anywhere}
/* Карусель листается вбок, как в приложении: слайды в ряд, следующий
   выглядывает краем. Пропорции у всех от первого кадра — правило площадки. */
.thp-media{margin-top:9px;display:flex;gap:1.6%;overflow-x:auto;scroll-snap-type:x mandatory;
  border-radius:12px;scrollbar-width:none;max-height:480px}
.thp-media::-webkit-scrollbar{display:none}
.thp-media.many .thp-slide{flex:0 0 88%}
/* Ширину слайду задаёт разметка: она посчитана из его же пропорций
   и общей высоты ленты, поэтому кадр не растягивается. */
.thp-slide{flex:0 0 auto;height:100%;scroll-snap-align:start;border-radius:12px;
  overflow:hidden;background:#17171b}
.thp-slide img{display:block;width:100%;height:100%;object-fit:cover}
.thp-video{position:relative;display:grid;place-items:center;width:100%;height:100%;background:#25262b}
.thp-video img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.thp-video>i{position:relative;display:grid;place-items:center;width:42px;height:42px;border-radius:50%;
  background:rgba(0,0,0,.55);color:#fff;font-style:normal;padding-left:3px}
.thp-count{margin-top:6px;font-size:11px;color:#7d7f8a}
.thp-bar{display:flex;gap:18px;margin-top:10px;color:#7d7f8a;font-size:14px}
.thp-len{margin-top:8px;font-size:var(--fs-sm);color:var(--dim)}
.thp-len.over{color:var(--danger)}

/* Лента X, тёмная тема «Lights out»: чистый чёрный фон, серые подписи,
   тонкая линия ветки от аватара к своему же ответу. Кадры лежат сеткой
   с двухпиксельными просветами — это её собственный макет, не такой,
   как карусель Threads, поэтому и стили свои. */
.tg-preview-column.x-skin{background:#000;color:#e7e9ea;border-left-color:#2f3336}
.x-skin .tg-preview-label{color:#71767b}
.x-skin .tg-preview-note{color:#5b6065}
.x-skin .tgp-audit{background:#1d1a0b;border-color:#6b5a20;color:#e8d9a6}
.x-skin .tgp-audit.bad{background:#2a1414;border-color:#7a3030;color:#f0c9c9}
.x-skin .thp-len{color:#71767b}
.xp-post{background:#000;border:1px solid #2f3336;border-radius:14px;padding:14px 15px;color:#e7e9ea}
.xp-row{display:grid;grid-template-columns:44px minmax(0,1fr);gap:10px}
.xp-row+.xp-row{margin-top:10px}
.xp-side{display:flex;flex-direction:column;align-items:center}
.xp-ava{width:40px;height:40px;border-radius:50%;display:grid;place-items:center;flex:0 0 auto;
  background:linear-gradient(140deg,#3d4045,#16181c);color:#fff;font-weight:700;font-size:15px;
  border:1px solid #2f3336}
.xp-row:not(:last-child) .xp-side::after{content:'';flex:1;width:2px;margin-top:6px;
  background:#2f3336;border-radius:2px}
.xp-head{display:flex;align-items:baseline;gap:5px;font-size:14px}
.xp-head .xp-at,.xp-head time{color:#71767b;font-size:14px}
.xp-text{margin-top:2px;font-size:15px;line-height:1.4;white-space:pre-wrap;overflow-wrap:anywhere}
/* Сетка кадров: пропорции всей плитки задаёт разметка, каждый кадр
   обрезается по центру — ровно так площадка и поступает. */
.xp-media{margin-top:10px;display:grid;gap:2px;border-radius:16px;overflow:hidden;
  border:1px solid #2f3336;background:#16181c;max-height:520px}
.xp-media.two{grid-template-columns:1fr 1fr}
.xp-media.three{grid-template-columns:1fr 1fr;grid-template-rows:1fr 1fr}
.xp-media.three .xp-cell.tall{grid-row:span 2}
.xp-media.four{grid-template-columns:1fr 1fr;grid-template-rows:1fr 1fr}
.xp-cell{position:relative;overflow:hidden;min-width:0;min-height:0;background:#16181c}
.xp-cell img{display:block;width:100%;height:100%;object-fit:cover}
.xp-bar{display:flex;justify-content:space-between;max-width:320px;margin-top:10px;
  color:#71767b;font-size:13px}
#capPrompt{font-size:12px;color:var(--dim)}

#modelSel{width:auto;min-width:130px;max-width:200px;margin:0;font-weight:500}
#modelRename{padding:6px 9px;line-height:1}

.bankgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(var(--card-w),1fr));gap:12px}
/* Источник нативного drag нельзя скрывать через display:none при переходе
   из банка в календарь — браузер оборвёт жест. Держим вкладку отрисованной,
   но далеко за экраном, пока мышь несёт карточку. */
#v-bank.bank-drag-source{display:block!important;position:fixed;left:-200vw;top:0;
  width:var(--page-w);pointer-events:none}
#v-bank .bankgrid{grid-template-columns:repeat(auto-fill,minmax(min(var(--card-w),132px),1fr));gap:9px}
.bcard{background:var(--surface);border:1px solid var(--line);border-radius:12px;overflow:hidden;cursor:grab;position:relative}
.bcard[draggable="false"]{cursor:pointer}
.bcard:active{cursor:grabbing}
.bcard .ph{aspect-ratio:3/4;background:var(--surface2);display:flex;align-items:center;justify-content:center;color:var(--muted);font-size:12px;overflow:hidden}
.bcard .ph img{width:100%;height:100%;object-fit:cover;display:block}
.bcard .b{padding:8px 9px}
.bcard .b b{font-size:calc(var(--fs-big) * .59);font-weight:500;display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bcard .b span{font-size:calc(var(--fs-sm) * .92);color:var(--dim)}
.tag{position:absolute;top:6px;left:6px;font-size:10.5px;padding:2px 7px;border-radius:99px;background:rgba(0,0,0,.62);color:#fff;backdrop-filter:blur(4px)}
.tag.w{background:var(--warn);color:#fff}
/* Рабочие статусы различаются цветом с первого взгляда: «Отснято» — тёплый,
   «В расписании» — синий. Предупреждение формата остаётся отдельной обводкой. */
.tag.status-shot{background:rgba(174,91,22,.92)}
.tag.status-ready{background:rgba(80,76,69,.92)}
.tag.status-scheduled{background:rgba(47,100,203,.92)}
.tag.status-published{background:rgba(45,122,78,.92)}
.tag.status-archived{background:rgba(92,92,98,.88)}
.tag.has-warn{box-shadow:0 0 0 2px var(--warn)}
.cnt{position:absolute;top:6px;right:6px;min-width:20px;height:20px;padding:0 6px;font-size:11px;font-weight:600;border-radius:99px;background:rgba(0,0,0,.72);color:#fff;display:flex;align-items:center;justify-content:center;backdrop-filter:blur(4px)}

/* Лента файлов внутри единицы банка */
.fstrip{display:flex;flex-wrap:wrap;gap:8px;margin:10px 0 2px}
.fitem{position:relative;width:72px;height:96px;border-radius:9px;overflow:hidden;background:var(--surface2);border:1px solid var(--line);flex:none}
.fitem img{width:100%;height:100%;object-fit:cover;display:block}
.fitem .noth{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:11px;color:var(--muted);text-transform:uppercase}
.fitem{cursor:grab}
.fitem:active{cursor:grabbing}
.fitem .fw{position:absolute;top:4px;left:4px;width:15px;height:15px;border-radius:99px;background:var(--warn);color:#fff;font-size:10px;font-weight:700;display:flex;align-items:center;justify-content:center;cursor:help}
.fitem .fnum{position:absolute;top:4px;right:4px;min-width:17px;height:17px;border-radius:99px;background:rgba(0,0,0,.75);color:#fff;font-size:10.5px;font-weight:700;display:flex;align-items:center;justify-content:center;backdrop-filter:blur(4px)}
.fitem .fx{position:absolute;left:0;right:0;bottom:0;display:flex;gap:1px;opacity:.85;transition:opacity .12s}
.fitem:hover .fx{opacity:1}
.fitem .fx button{flex:1;border:none;padding:4px 0;font-size:12px;line-height:1;background:rgba(0,0,0,.72);color:#fff;cursor:pointer}
.fitem .fx button:hover:not(:disabled){background:rgba(0,0,0,.92)}
.fitem .fx button:disabled{opacity:.3;cursor:default}
.fitem.drag{opacity:.35}
.fitem.over{outline:2px solid var(--accent);outline-offset:1px}

.fadd{width:72px;height:96px;flex:none;border:1.5px dashed var(--line2);border-radius:9px;display:flex;align-items:center;justify-content:center;text-align:center;font-size:11px;line-height:1.35;color:var(--muted);cursor:pointer;transition:.12s}
.fadd:hover{border-color:var(--accent);color:var(--accent)}
.fadd.over{border-color:var(--accent);background:var(--accent-bg);color:var(--accent)}

.drop{border:1.5px dashed var(--line2);border-radius:14px;padding:26px;text-align:center;color:var(--dim);background:var(--surface);margin-bottom:14px}
.drop.over{border-color:var(--accent);background:var(--accent-bg);color:var(--accent)}

table{width:100%;border-collapse:collapse}
th{text-align:left;font-size:11.5px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);font-weight:500;padding:8px 10px;border-bottom:1px solid var(--line)}
td{padding:9px 10px;border-bottom:1px solid var(--line);font-size:13.5px}
tr:last-child td{border-bottom:none}
.bar{height:6px;border-radius:99px;background:var(--surface2);overflow:hidden;min-width:70px;flex:1}
.bar i{display:block;height:100%}
.badge{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--dim)}
/* В запасах площадка читается тем же фирменным значком, что в календаре.
   Цветная точка обозначала тип и не отвечала на главный вопрос — куда он идёт. */
#stockTable .stock-type .pf{display:inline-flex;align-items:center;flex:0 0 auto}
#stockTable .stock-type .pf :is(svg,.pfimg){width:15px;height:15px;display:block;object-fit:contain}
#stockTable .stock-type .pfm{display:inline-grid;place-items:center;width:15px;height:15px;
  font-size:9px;font-style:normal;font-weight:800;line-height:1;
  border:1.5px solid currentColor;border-radius:3.5px}
#stockTable .stock-sort{display:inline-flex;align-items:center;gap:4px;padding:0;border:0;
  background:transparent;color:inherit;font:inherit;text-transform:inherit;letter-spacing:inherit;
  cursor:pointer}
#stockTable .stock-sort:hover{color:var(--accent)}
#stockTable .stock-sort span{font-size:13px;line-height:1}
/* Обложка публикации в таблице аналитики: опознаётся глазами быстрее текста. */
.igth{width:44px;height:58px;object-fit:cover;border-radius:6px;display:block;background:var(--surface2)}
.ig-cover-action{display:block;width:44px;height:58px;margin:0;padding:0;border:0;border-radius:6px;
  overflow:hidden;background:var(--surface2);color:var(--dim);font:inherit;cursor:pointer;box-shadow:none}
.ig-cover-action:hover,.ig-cover-action:focus-visible{outline:2px solid color-mix(in srgb,var(--accent) 55%,transparent);outline-offset:2px}
.ig-cover-action.empty{display:grid;place-items:center;font-size:14px;letter-spacing:1px}
/* Подписки по рилсам вписываются руками — узкое поле прямо в ячейке. */
.fman{width:62px;margin:0;padding:3px 6px;font-size:12.5px;font-weight:600;text-align:right;
  border:1px dashed var(--line2);background:transparent;border-radius:6px}
.fman:focus{border-style:solid;border-color:var(--accent);background:var(--surface)}
#igTable{width:100%;min-width:100%;table-layout:fixed}
#igTable th{cursor:pointer;user-select:none;white-space:normal;line-height:1.15;padding:7px 4px;font-size:10px}
#igTable th:hover{color:var(--accent)}
#igTable td{vertical-align:middle;padding:7px 4px;white-space:nowrap;font-size:12px;font-weight:400}
#igTable .ig-key{font-weight:600}
#igTable th[data-c="strength"]{color:#bd4f5c;font-weight:800;background:color-mix(in srgb,#d9606d 10%,var(--surface))}
#igTable td.ig-strength-cell{padding:4px 6px;text-align:center;background:color-mix(in srgb,#d9606d 8%,var(--surface))}
.ig-strength-score{min-width:0;padding:0;border:0;background:transparent;color:#bd4f5c;
  font-family:inherit;font-size:inherit;font-weight:800;line-height:inherit;cursor:pointer;box-shadow:none}
.ig-strength-score:hover,.ig-strength-score:focus-visible{color:#a63f4c;text-decoration:underline;
  text-underline-offset:2px;outline:none}
.ig-strength-pop{display:none;position:fixed;z-index:220;width:340px;max-width:calc(100vw - 24px);padding:14px;
  border:1px solid color-mix(in srgb,#d9606d 28%,var(--line));border-radius:14px;background:var(--surface);
  color:var(--text);box-shadow:0 16px 48px rgba(35,24,27,.22);white-space:normal;text-align:left}
.ig-strength-pop.on{display:block}
.igsp-top{display:flex;align-items:center;justify-content:space-between;color:#bd4f5c;font-weight:750;margin-bottom:10px}
.igsp-top b{font-size:25px;line-height:1}
.igsp-title{font-weight:750;color:#bd4f5c;margin-bottom:5px}
.ig-strength-pop p{font-size:12.5px;line-height:1.45;margin:0;color:var(--dim)}
.igsp-parts{display:grid;gap:7px}
.igsp-part>div{display:flex;align-items:baseline;justify-content:space-between;font-size:12px}
.igsp-part>div>span{font-weight:600}
.igsp-part b{display:flex;align-items:baseline;gap:6px;font-size:12px}
.igsp-part small{font-size:10.5px;font-weight:400;color:var(--muted)}
.igsp-part>i{display:block;height:4px;margin-top:3px;border-radius:99px;background:var(--surface2);overflow:hidden}
.igsp-part>i>em{display:block;height:100%;border-radius:inherit;background:color-mix(in srgb,#d9606d 58%,var(--muted));font-style:normal}
.igsp-part.best>div>span,.igsp-part.best b{color:#bd4f5c}
.igsp-part.best>i>em{background:#d9606d}
.igsp-note{margin-top:10px;padding:8px 9px;border-radius:9px;background:var(--surface2);font-size:11.5px;line-height:1.42}
.igsp-note.best{background:color-mix(in srgb,#d9606d 9%,var(--surface2))}
.igsp-formula{margin-top:9px;color:var(--muted);font-size:9.5px;line-height:1.35}
.metric-help{display:inline-flex;align-items:center;gap:4px}
.metric-help i{display:inline-grid;place-items:center;width:16px;height:16px;border:1px solid var(--line2);
  border-radius:50%;font-size:10px;font-style:normal;line-height:1;color:var(--dim);text-transform:none}
.metric-help:hover i{border-color:var(--accent);color:var(--accent);background:var(--accent-bg)}
.ig-archived td{background:color-mix(in srgb,var(--surface2) 55%,transparent);color:var(--dim)}
.ig-empty{text-align:center;padding:26px 12px}

.dot{width:7px;height:7px;border-radius:50%;flex:0 0 auto;display:inline-block;vertical-align:middle;background:var(--c,var(--line2))}

.drawer{position:fixed;top:0;right:0;bottom:0;width:400px;max-width:92vw;background:var(--surface);border-left:1px solid var(--line);z-index:60;padding:18px;overflow-y:auto;transform:translateX(100%);transition:transform .18s ease}
.drawer.on{transform:none}
.scrim{position:fixed;inset:0;background:rgba(0,0,0,.35);z-index:50;opacity:0;pointer-events:none;transition:opacity .18s}
.scrim.on{opacity:1;pointer-events:auto}
.drawer h3{margin:0 0 2px;font-size:16px;font-weight:600}
.prev{width:100%;border-radius:10px;margin:12px 0;background:var(--surface2);display:block}
.preview-pack{margin:12px 0}
.preview-pack .prev{margin:0}
.preview-pack.many{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px}
.preview-pack.many .prev{height:220px;object-fit:cover}
.warnbox{background:var(--warn-bg);color:var(--warn);border-radius:10px;padding:9px 11px;font-size:12.5px;margin:10px 0}
.errbox{background:var(--bad-bg);color:var(--bad);border-radius:10px;padding:9px 11px;font-size:12.5px;margin:10px 0}
.okbox{background:var(--ok-bg);color:var(--ok);border-radius:10px;padding:9px 11px;font-size:12.5px;margin:10px 0}

/* Разборы от разных моделей — колонками рядом, чтобы сравнивать взглядом.
   На узком экране колонки схлопываются в один столбец сами. */
.brfs{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:12px;align-items:start}
.brf.harsh{border-color:var(--bad)}

/* Разделы настроек сворачиваются. Заголовок остаётся кликабельным целиком,
   стрелка слева поворачивается — без неё непонятно, что блок раскрывается. */
details.card{padding:0}
details.card>summary{list-style:none;cursor:pointer;padding:14px 16px;display:flex;align-items:center;gap:9px;
  font-size:calc(var(--fs-big) * .64);font-weight:600;border-radius:14px;user-select:none}
details.card>summary::-webkit-details-marker{display:none}
details.card>summary::before{content:'';width:6px;height:6px;flex:0 0 auto;
  border-right:2px solid var(--muted);border-bottom:2px solid var(--muted);
  transform:rotate(-45deg);transition:transform .18s ease;margin-left:2px}
details.card[open]>summary::before{transform:rotate(45deg)}
details.card>summary:hover{background:var(--surface2)}
details.card[open]>summary{border-radius:14px 14px 0 0}
details.card .dbody{padding:0 16px 16px}
details.card>summary .note{margin-left:auto;font-size:var(--fs-sm);font-weight:400;color:var(--muted)}

/* Предпросмотр: настоящая ячейка календаря с настоящими плашками, поэтому
   реагирует на переменные сама, без единой строчки кода на перерисовку. */
.lookprev{position:sticky;top:60px;z-index:5;background:var(--surface);
  margin:0 -16px 2px;padding:10px 16px 12px;border-bottom:1px solid var(--line)}
.lookprev .day{max-width:340px}

/* Панель внешнего вида: ползунки в две-три колонки, текущее значение
   прижато к правому краю подписи, чтобы читалось как цифра, а не как слово. */
.lookgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:4px 18px}
.lookgrid label{display:flex;flex-wrap:wrap;align-items:baseline;margin:8px 0 0}
.lookgrid .lkv{margin-left:auto;font-variant-numeric:tabular-nums;color:var(--txt);font-weight:600}
.lookgrid input[type=range]{width:100%;margin:2px 0 0;padding:0;accent-color:var(--accent)}
/* Пипетка — квадратик цвета, а не поле во всю ширину: общее правило для input
   растягивало её в тонкую полоску, по которой цвет было не разобрать. */
.lookgrid input[type=color]{width:38px;height:26px;min-width:0;flex:0 0 auto;margin:2px 8px 0 0;
  padding:2px;border:1px solid var(--line2);border-radius:7px;background:var(--surface);cursor:pointer}
.lookgrid input[type=color]::-webkit-color-swatch-wrapper{padding:0}
.lookgrid input[type=color]::-webkit-color-swatch{border:0;border-radius:4px}
/* Подпись с кодом цвета встаёт рядом с пипеткой, а не улетает к правому краю. */
.lookgrid label:has(input[type=color]) .lkv{margin-left:0}
.lookgrid select{margin-top:2px}
/* Перетаскивание в банке: полоса показывает, куда карточка встанет.
   Слева от курсора — перед соседкой, справа — после неё. */
.bcard.dragging{opacity:.45}
.bcard.dropL,.bcard.dropR{position:relative}
.bcard.dropL::before,.bcard.dropR::before{content:'';position:absolute;top:0;bottom:0;width:3px;
  background:var(--accent);border-radius:2px;z-index:2}
.bcard.dropL::before{left:-6px} .bcard.dropR::before{right:-6px}

/* Перевод часов у аудитории: разница поясов меняется, и время публикаций
   в её часах сдвигается. Полоса висит несколько дней вокруг даты перехода. */
.dstbox{background:var(--warn-bg);color:var(--warn);border:1px solid var(--warn);
  border-radius:12px;padding:10px 14px;margin-bottom:14px;font-size:var(--fs-sm);
  display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.dstbox b{font-weight:600}
.dstbox button{margin-left:auto}

/* Выбор контента в слот: сетка кадров вместо выпадающего списка — по имени
   файла вроде lauren_face_fixed_00456 всё равно ничего не понять, а по кадру
   видно сразу. Нажатие ставит пост в слот. */
.pick{display:grid;grid-template-columns:repeat(auto-fill,minmax(74px,1fr));gap:8px;margin-top:4px}
.slot-pick{border:1px solid var(--line);border-radius:10px;background:var(--surface);overflow:hidden}
.slot-pick>summary{cursor:pointer;list-style:none;padding:9px 11px;color:var(--dim);font-size:13px;
  display:flex;align-items:center;gap:7px}
.slot-pick>summary::-webkit-details-marker{display:none}
.slot-pick>summary::before{content:'›';font-size:17px;line-height:1;color:var(--muted);transition:transform .12s}
.slot-pick[open]>summary::before{transform:rotate(90deg)}
.slot-pick>summary span{margin-left:auto;color:var(--muted);font-size:11px}
.slot-pick[open]>summary{border-bottom:1px solid var(--line);background:var(--surface2)}
.slot-pick .pick{padding:8px;margin:0}
.pk{position:relative;cursor:pointer;border:2px solid transparent;border-radius:9px;overflow:hidden;
  background:var(--surface2);transition:border-color .12s, transform .12s}
.pk:hover{border-color:var(--line2);transform:translateY(-1px)}
.pk.on{border-color:var(--accent)}
.pk img{width:100%;aspect-ratio:3/4;object-fit:cover;display:block}
.pk .noimg,.pk.none{display:flex;align-items:center;justify-content:center;text-align:center;
  aspect-ratio:3/4;color:var(--dim);font-size:calc(var(--fs-sm) * .8);line-height:1.3;padding:4px}
.pk.none{border:1px dashed var(--line2);background:transparent}
.pk.none:hover{border-color:var(--bad);color:var(--bad)}
/* Уже опубликованное среди кандидатов слота: выбор такой плитки не планирует
   пост заново, а записывает факт публикации в этот слот. */
.pk.pkdone{border-color:color-mix(in srgb,var(--ok) 45%,var(--line))}
.pk .busy.done{background:var(--ok);color:#fff}
/* Подпись под кадром: имя файла целиком не влезет, но начало опознаётся. */
.pk .cap{display:block;padding:3px 4px;font-size:calc(var(--fs-sm) * .72);color:var(--dim);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background:var(--surface)}
/* Пост уже стоит в другом дне — показываем, в каком. */
.pk .busy{position:absolute;top:3px;right:3px;background:var(--warn);color:#fff;
  font-size:calc(var(--fs-sm) * .68);padding:1px 5px;border-radius:99px;font-variant-numeric:tabular-nums}

/* Предупреждение о дубле: кадры рядом, чтобы решать глазами, а не по числу. */
.dupe{border:1px solid var(--warn);background:var(--warn-bg);border-radius:12px;padding:10px 12px;margin:10px 0}
.dupehead{font-size:var(--fs-sm);color:var(--warn);margin-bottom:8px}
.duperow{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px}
.duperow figure{margin:0;width:92px}
.duperow img{width:92px;height:92px;object-fit:cover;border-radius:8px;display:block;background:var(--surface2)}
.duperow figcaption{font-size:calc(var(--fs-sm) * .84);color:var(--dim);margin-top:3px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* Разнообразие: доля самого частого значения полосой. Красная полоса —
   не ошибка, а повод разбавить. */
.divrow{display:grid;grid-template-columns:110px 1fr 62px;gap:10px;align-items:center;padding:5px 0}
.divbar{height:8px;border-radius:99px;background:var(--surface2);overflow:hidden}
.divbar i{display:block;height:100%;background:var(--accent);border-radius:99px}
.divbar.warn i{background:var(--warn)} .divbar.bad i{background:var(--bad)}
.divval{font-size:var(--fs-sm);color:var(--dim);text-align:right;font-variant-numeric:tabular-nums}
.divvals{font-size:calc(var(--fs-sm) * .92);color:var(--muted);margin-top:1px}

/* Редактор признаков: строка на признак, значения через запятую. */
.trrow{display:grid;grid-template-columns:150px 1fr 34px;gap:8px;align-items:center;margin-bottom:6px}

/* Референсы. Карточка та же, что в банке, — вкладка должна ощущаться
   продолжением банка, а не отдельной программой. Отличия только там,
   где реф правда другой: он не перетаскивается и у него бывает
   ссылка без файла. */
.bcard.ref,.bcard.blank{cursor:pointer}
.bcard.ref .ph{aspect-ratio:9/16}
.ref-used-check{position:absolute;top:6px;left:6px;z-index:2;display:flex;align-items:center;gap:4px;
  padding:3px 7px;border-radius:99px;background:rgba(0,0,0,.68);color:#fff;font-size:10.5px;
  line-height:1;cursor:pointer;backdrop-filter:blur(4px)}
.ref-used-check input{width:auto;margin:0;accent-color:#45a66d}
.ref-used-check.on{background:rgba(45,122,78,.92)}
.bcard.ref .tag{top:34px}
.reflink{font-size:calc(var(--fs-sm) * .92);color:var(--muted);border:1px dashed var(--line2);
  border-radius:99px;padding:3px 10px}
/* Ссылка «Открыть источник» стоит в ряду с кнопками — пусть и выглядит так же. */
a.btn{display:inline-block;text-decoration:none;font:inherit;cursor:pointer;
  border:1px solid var(--line2);background:var(--surface);color:var(--txt);
  border-radius:var(--r);padding:7px 13px;transition:background .12s,border-color .12s}
a.btn:hover{background:var(--surface2)}
a.btn.sm{padding:4px 9px;font-size:calc(var(--fs-big) * .59)}

/* Редактор. Сцена слева, ручки справа: рамку двигают глазами по картинке,
   а к кнопкам обращаются, когда кадр уже найден. */
.edwrap{display:grid;grid-template-columns:1fr 320px;gap:14px;align-items:start}
/* Сцена прилипает под шапкой: панель ручек длиннее картинки, и пока
   докрутишь до цвета, кадр уезжал за верх экрана — а править цвет,
   не видя кадра, невозможно. 74px — та же ступенька, что у превью
   промптов. Картинка ограничена 68vh, поэтому целиком помещается. */
.edstage{background:var(--surface2);border:1px solid var(--line);border-radius:14px;
  min-height:340px;display:flex;align-items:center;justify-content:center;padding:14px;overflow:hidden;
  position:sticky;top:74px}
.edempty{color:var(--dim);text-align:center;font-size:var(--fs-sm);line-height:1.6}
/* Обёртка ужимается ровно по картинке — рамке нужна её настоящая рамка,
   а не рамка сцены, иначе доли поедут. */
.edbox{position:relative;display:inline-block;line-height:0;touch-action:none}
/* Клиповать надо только картинку, не всю edbox: ручки рамки выступают наружу
   на семь пикселей и исчезли бы вместе с повёрнутыми краями. */
.edimage{position:relative;overflow:hidden;line-height:0}
.edbox img{display:block;max-width:100%;max-height:68vh;user-select:none;-webkit-user-drag:none;
  transform-origin:center center;will-change:transform}
.edgrain{position:absolute;inset:0;pointer-events:none;background-repeat:repeat;mix-blend-mode:soft-light}
/* Холст поворота оттенка лежит поверх картинки в той же коробке и повторяет
   её преобразование. Показывается, только когда поворот не нулевой: пока он
   ноль, картинка и холст неотличимы, а <img> дешевле. */
#edSkinCv{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none;
  transform-origin:center center;will-change:transform;display:none}
.edflip.on,.edmove.on,.edpip.on{background:var(--accent);border-color:var(--accent);color:#fff}
.edbox.moving .edimage{cursor:grab;touch-action:none}
.edbox.moving .edimage:active{cursor:grabbing}
.edbox.moving .edframe{pointer-events:none}
/* Пипетка: рамка кропа не должна перехватывать клик, он весь про цвет. */
.edbox.picking{cursor:crosshair}
.edbox.picking .edframe,.edbox.picking .edframe i{pointer-events:none;cursor:crosshair}

.edscope{margin-top:10px}
.edscope canvas{display:block;width:100%;max-width:230px;height:auto;border-radius:10px;
  background:#0d0f12;border:1px solid var(--line);touch-action:none}
#edCurve{cursor:crosshair}
.edsub{display:block;margin:14px 0 6px;font-size:calc(var(--fs-big) * .58)}
/* Чипы секторов: точка снизу горит там, где уже накручено, — иначе забытый
   сектор ищется вслепую по шести штукам. */
.edsects{display:flex;flex-wrap:wrap;gap:5px}
.edsects .sect{position:relative;padding:4px 9px}
.edsects .sect.has::after{content:'';position:absolute;left:50%;bottom:3px;transform:translateX(-50%);
  width:4px;height:4px;border-radius:50%;background:var(--accent)}
.edsects .sect.on.has::after{background:#fff}
.edsects .sect.on{background:var(--accent);border-color:var(--accent);color:#fff}

/* Затемнение снаружи рамки одной тенью: четыре отдельных блока пришлось бы
   пересчитывать на каждый пиксель перетаскивания. */
.edframe{position:absolute;box-sizing:border-box;border:1.5px solid #fff;cursor:move;
  box-shadow:0 0 0 9999px rgba(0,0,0,.55);
  background-image:linear-gradient(to right,transparent 33.33%,rgba(255,255,255,.35) 33.33%,rgba(255,255,255,.35) 33.5%,transparent 33.5%,transparent 66.66%,rgba(255,255,255,.35) 66.66%,rgba(255,255,255,.35) 66.83%,transparent 66.83%),
    linear-gradient(to bottom,transparent 33.33%,rgba(255,255,255,.35) 33.33%,rgba(255,255,255,.35) 33.5%,transparent 33.5%,transparent 66.66%,rgba(255,255,255,.35) 66.66%,rgba(255,255,255,.35) 66.83%,transparent 66.83%)}
.edframe i{position:absolute;width:14px;height:14px;background:#fff;border-radius:3px;
  box-shadow:0 1px 3px rgba(0,0,0,.5)}
.edframe i[data-h="nw"]{left:-7px;top:-7px;cursor:nwse-resize}
.edframe i[data-h="ne"]{right:-7px;top:-7px;cursor:nesw-resize}
.edframe i[data-h="se"]{right:-7px;bottom:-7px;cursor:nwse-resize}
.edframe i[data-h="sw"]{left:-7px;bottom:-7px;cursor:nesw-resize}
.edframe i[data-h="n"]{left:50%;top:-7px;margin-left:-7px;cursor:ns-resize}
.edframe i[data-h="s"]{left:50%;bottom:-7px;margin-left:-7px;cursor:ns-resize}
.edframe i[data-h="w"]{left:-7px;top:50%;margin-top:-7px;cursor:ew-resize}
.edframe i[data-h="e"]{right:-7px;top:50%;margin-top:-7px;cursor:ew-resize}
/* При запертом соотношении середины сторон не работают: тянуть одну сторону
   с фиксированной пропорцией — это то же, что тянуть угол, только запутаннее. */
.edframe.locked i[data-h="n"],.edframe.locked i[data-h="s"],
.edframe.locked i[data-h="w"],.edframe.locked i[data-h="e"]{display:none}

/* Коллаж. Сетка держит форму холста, ячейки делят её поровну.
   Ни gap, ни border здесь быть не может: между кадрами не должно быть
   ничего — это условие задачи, а не оформление. */
/* Сцена коллажа высокая и с определённой высотой — от неё считается холст. */
.edstage.stage-cl{height:min(78vh, 1000px);align-items:center}
/* Размер обёртки назначает JS в пикселях, и это не придирка к стилям.
   Раньше здесь стояли aspect-ratio без ширины и высоты: обёртка была
   флекс-элементом и брала размер из содержимого. Пока хоть одна ячейка
   пустая, внутри лежит текст «нажми, чтобы выбрать» — размер есть.
   Стоит заполнить последнюю, и всё содержимое становится либо фоном,
   либо абсолютно спозиционированными кнопками, то есть нулевым по потоку:
   холст схлопывался в ничто ровно на четвёртом фото. */
.clwrap{background:var(--surface);border:1px solid var(--line);
  border-radius:10px;overflow:hidden;flex:none}
.clgrid{display:grid;width:100%;height:100%;gap:0}
.clcell{position:relative;overflow:hidden;background:var(--surface2);
  background-size:cover;background-repeat:no-repeat;cursor:grab;touch-action:none}
.clcell:active{cursor:grabbing}
.clcell.empty{display:flex;align-items:center;justify-content:center;cursor:pointer;
  color:var(--muted);font-size:calc(var(--fs-sm) * .92);text-align:center;padding:6px}
/* Обводка активной ячейки нарисована внутрь: наружная сдвинула бы соседей
   и в кадре появился бы тот самый шов, которого быть не должно. */
.clcell.on::after{content:'';position:absolute;inset:0;box-shadow:inset 0 0 0 2px var(--accent);pointer-events:none}
.clcell .fx{position:absolute;top:4px;right:4px;display:flex;gap:3px;opacity:0;transition:.12s}
.clcell:hover .fx{opacity:1}
.clcell .fx button{padding:1px 6px;font-size:11px;line-height:1.5;background:rgba(0,0,0,.6);
  color:#fff;border-color:transparent;backdrop-filter:blur(4px)}
.clcell .fx button:hover{background:rgba(0,0,0,.85)}

/* Подсказка при перетаскивании файлов на вкладку редактора. Висит поверх,
   чтобы не двигать разметку: сдвиг под курсором с файлом читается как сбой. */
#v-edit{position:relative}
.edtip{position:absolute;inset:0;z-index:20;display:none;align-items:center;justify-content:center;
  border:2px dashed var(--accent);border-radius:14px;background:var(--accent-bg);
  color:var(--accent);font-size:calc(var(--fs-big) * .8);pointer-events:none}
.edtip.on{display:flex}
/* Только что принесённое помечаем — среди сотни кадров банка иначе не найти. */
.pk.fresh{outline:2px solid var(--accent);outline-offset:-2px}
.drop.edrop{margin-bottom:0}

.edratios{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.edratios button{padding:5px 11px;font-size:calc(var(--fs-big) * .59)}
.edratios button.on{background:var(--accent);border-color:var(--accent);color:#fff}
.edpxrow{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);gap:7px;align-items:center;margin-top:6px}
.edpxrow input{min-width:0;font-variant-numeric:tabular-nums}
.edpxrow button{grid-column:1/-1;justify-self:start}
.edsize{margin-top:10px;font-size:var(--fs-sm);color:var(--dim);font-variant-numeric:tabular-nums}
.edsize b{color:var(--txt);font-variant-numeric:tabular-nums}

/* В одну колонку липкая сцена съела бы весь экран, а ручки остались бы
   в щели внизу — там прокручиваем как обычно. */
@media (max-width:1000px){ .edwrap{grid-template-columns:1fr} .edstage{position:static} }

/* Показатели статистики: любую цифру можно вписать руками. Ячейка
   становится полем по нажатию — держать полсотни строк по семь полей
   постоянно незачем, таблицу в основном читают. */
td.ige{cursor:text}
td.ige:hover{background:var(--surface2)}
/* Процент выглядел нередактируемым, и было неоткуда узнать, что за ним
   стоит количество. Подчёркивание при наведении показывает, что цифру
   можно вписать. */
td.ige:hover .ig-value{border-bottom:1.5px dotted var(--line2)}
/* Вписанное руками помечаем: через месяц надо понимать, где цифра из API,
   а где своя из приложения инстаграма. */
td.ige.hand .ig-value{border-bottom:1.5px dotted var(--accent);color:var(--accent)}
td.ige.hand:hover .ig-value{border-bottom-color:var(--accent)}

/* Поле ручного ввода. Висит на body и привязано к ячейке: карточка таблицы
   прокручивается вбок, и вложенное поле она бы обрезала. Вписывается всегда
   количество — процент считается тут же, пока набираешь. */
.ig-edit-pop{display:none;position:fixed;z-index:230;width:158px;padding:8px 9px;
  border:1px solid var(--line2);border-radius:11px;background:var(--surface);
  box-shadow:0 12px 32px rgba(35,24,27,.2);white-space:normal;text-align:left}
.ig-edit-pop.on{display:block}
.igep-t{margin-bottom:5px;font-size:10px;font-weight:750;letter-spacing:.3px;
  text-transform:uppercase;color:var(--dim)}
.ig-edit-pop input.fman{width:100%;margin:0;padding:4px 6px;font-size:14px;text-align:left}
.ig-edit-pop input.fman.bad{border-style:solid;border-color:var(--bad);color:var(--bad)}
.igep-r{margin-top:5px;font-size:11px;line-height:1.35;color:var(--dim);
  font-variant-numeric:tabular-nums}
.ig-anomaly{background:var(--warn-bg);color:var(--warn)}
.ig-anomaly-mark{font-weight:600}

/* Пипетка цвета в таблице типов. */
.tcol{width:34px;height:24px;padding:0;border-radius:6px;border:1px solid var(--line2);background:none;cursor:pointer}
/* Заголовки в одну строку: они набраны прописными с разрядкой, и «В ПЛАНЕ»
   в узкой колонке ломалось пополам. Ширина подстроится сама. */
#normsTable th{padding:5px 8px;white-space:nowrap}
#normsTable td{padding:4px 8px;height:34px;vertical-align:middle}
#normsTable .nD,#normsTable .nT{padding:4px 7px;line-height:1.2}
#normsTable .tacts{display:flex;align-items:center;gap:2px;flex-wrap:nowrap;white-space:nowrap}
#normsTable .tacts button{padding:2px 5px;line-height:1.2}
#normsTable .tacts .tDel{font-size:15px}

/* Выключенный тип в таблице норм: видно, но приглушённо. */
#normsTable tr.off td{opacity:.5}
#normsTable tr.off .badge{text-decoration:line-through}

#toast{position:fixed;left:50%;bottom:24px;transform:translateX(-50%) translateY(80px);background:var(--txt);color:var(--bg);padding:10px 18px;border-radius:99px;font-size:13.5px;z-index:90;opacity:0;transition:.2s;pointer-events:none}
#toast.on{opacity:1;transform:translateX(-50%)}
.switch{display:inline-flex;align-items:center;gap:9px;cursor:pointer;font-size:14px}
.switch input{width:auto;margin:0}
.logline{font-size:12px;padding:5px 0;border-bottom:1px solid var(--line);display:flex;gap:9px}
.logline time{color:var(--muted);font-variant-numeric:tabular-nums;flex:0 0 auto}

@media (max-width:820px){
  main{padding:12px}
  header{padding:9px 12px;gap:10px}
  .hdrpill{display:none}
  .dow,.grid,.calwrap{display:none}
  .agenda{display:flex}
  .drawer{width:100%;border-left:none}
  .kpis{grid-template-columns:repeat(2,1fr)}
  .todoadd{grid-template-columns:1fr}
  .todoadd button{justify-self:start}
  .todocalwrap{overflow-x:auto;padding-bottom:8px}
  .tododow,.todogrid{min-width:1050px}
  .gen-head{align-items:stretch;flex-direction:column}
  .gen-controls{justify-content:flex-start}
  .gen-traits{grid-template-columns:repeat(auto-fill,minmax(230px,1fr))}
  .gen-rule-card{grid-template-columns:1fr}
  .gen-rule-card-actions{justify-content:flex-start}
  .gen-output{position:static}
  .gen-title-row input{width:100%;order:3}
}

/* Кружок из видео. Круглая рамка, а не квадратная: Telegram обрежет кадр
   именно так, и показывать квадрат значило бы обещать углы, которых
   в результате не будет. Затемнение вокруг — тенью наружу от круга. */
/* Видео заполняет рамку ровно, без чёрных полей: координаты круга — проценты
   от рамки, и любая кайма сдвинула бы их относительно кадра. Поэтому высоту
   ограничивает не видео, а ширина обёртки, считанная по пропорциям ролика
   в openNoteMaker. */
.notewrap{position:relative;width:100%;margin:0 auto;background:#000;
  border-radius:10px;overflow:hidden;line-height:0}
.notewrap video{width:100%;height:auto;display:block}
.notesq{position:absolute;border:2px solid rgba(255,255,255,.9);border-radius:50%;
  box-shadow:0 0 0 9999px rgba(0,0,0,.5);cursor:grab;touch-action:none}
.notesq:active{cursor:grabbing}

/* Обрезка видео: две прозрачные шкалы лежат на одной дорожке, поэтому края
   фрагмента двигаются независимо, а сиреневая полоса показывает итог целиком. */
.videoeditstage{position:relative;max-width:100%;margin:0 auto;background:#000;
  border-radius:10px;overflow:hidden}
.videoeditstage .videoeditpreview{position:absolute;left:50%;top:50%;display:block;
  max-width:none;max-height:none;background:#000;transform-origin:center}
.video-rotate button.active{border-color:var(--accent);color:var(--accent);
  box-shadow:0 0 0 1px color-mix(in srgb,var(--accent) 35%,transparent)}
.trimhead{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  margin-bottom:8px;font-size:13px}
.trimrange{position:relative;height:30px;margin:0 8px}
.trimrange::before{content:"";position:absolute;left:0;right:0;top:13px;height:4px;
  border-radius:99px;background:var(--line)}
.trimfill{position:absolute;top:13px;height:4px;border-radius:99px;background:var(--accent)}
.trimrange input[type="range"]{position:absolute;inset:0;width:100%;height:30px;margin:0;padding:0;
  appearance:none;-webkit-appearance:none;background:transparent;pointer-events:none}
.trimrange input[type="range"]::-webkit-slider-runnable-track{height:4px;background:transparent}
.trimrange input[type="range"]::-webkit-slider-thumb{width:18px;height:18px;margin-top:-7px;
  appearance:none;-webkit-appearance:none;border:2px solid var(--surface);border-radius:50%;
  background:var(--accent);box-shadow:0 1px 5px rgba(0,0,0,.35);pointer-events:auto;cursor:ew-resize}
.trimrange input[type="range"]::-moz-range-track{height:4px;background:transparent}
.trimrange input[type="range"]::-moz-range-thumb{width:16px;height:16px;border:2px solid var(--surface);
  border-radius:50%;background:var(--accent);pointer-events:auto;cursor:ew-resize}
.trimtimes{display:grid;grid-template-columns:1fr 1fr;gap:9px}
.trimtimes label{margin:0;font-size:12px;color:var(--muted)}
.trimtimes input{margin-top:4px;font-variant-numeric:tabular-nums}

/* Видео-промпты: слева конструктор, справа готовый промпт.

   Два столбца только здесь, у фото-половины раскладка своя: там результат
   идёт под работой, потому что промптов там пачка и они длинные. Тут же
   собранный промпт один, и держать его перед глазами при правке блоков —
   главное, ради чего конструктор и нужен. */
.vp-work{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,1fr);
  gap:14px;align-items:start}
/* Результат не уезжает вверх, пока листаешь блоки. Отступ — под липкую шапку. */
.vp-work .gen-output{position:sticky;top:74px;margin-top:0}

.vp-block{margin-bottom:10px;padding:9px 10px;border:1px solid var(--line);border-radius:10px;background:var(--bg)}
.vp-block-head{gap:6px;align-items:center;margin-bottom:6px}
.vp-block-head b{font-size:12px;font-weight:750;letter-spacing:.4px;text-transform:uppercase}
.vp-block-head select{width:auto;min-width:150px;padding:3px 22px 3px 7px;font-size:12px;margin:0}
/* Блоки Seedance длинные — Action легко уходит на десяток строк. Поле пониже
   заставляло бы листать внутри поля, листая при этом и страницу. */
.vp-block textarea{margin:0;min-height:150px;font-size:var(--fs-sm);line-height:1.45}
/* Собранный промпт читается как текст, а не как поле ввода: подписи блоков
   жирные, между блоками пустая строка — ровно то, что уедет в буфер. */
.vp-preview{margin-top:10px;padding:12px 14px;border:1px solid var(--line);border-radius:10px;
  background:var(--bg);font-size:var(--fs-sm);line-height:1.55;white-space:normal;
  max-height:66vh;overflow:auto}
.vp-preview:empty{display:none}
.vp-preview b{font-weight:700}

/* Узкий экран: столбцы складываются друг под друга, липкость снимается —
   иначе результат закрывал бы половину экрана над блоками. */
@media (max-width:1100px){
  .vp-work{grid-template-columns:1fr}
  .vp-work .gen-output{position:static;margin-top:14px}
  .vp-block textarea{min-height:110px}
}

/* Состав телеграм-поста в карточке банка. Отбит рамкой: это не ещё одно поле
   единицы, а отдельная часть — то, чем пост станет в канале. */
.ipost{margin-top:14px;padding:10px 12px;border:1px solid var(--line);border-radius:10px;
  background:var(--bg)}
.ipost label:first-of-type{margin-top:0}
.ip-btn-row{display:flex;gap:6px;align-items:center;margin-bottom:5px}
.ip-btn-style{width:112px;flex:0 0 112px;margin:0;padding:4px 25px 4px 7px;font-size:11px}
.poll-emoji{width:104px;flex:0 0 104px;margin:0;padding-left:8px;padding-right:6px}
@media (max-width:520px){.poll-emoji{width:78px;flex-basis:78px}}

/* Редактор Telegram слева, живой макет поста у правого края. Панель шире
   только для Telegram-карточек; остальные редакторы остаются прежними. */
.drawer.tg-compose-open{width:min(940px,96vw);max-width:96vw;padding:0;overflow:hidden;
  display:grid;grid-template-columns:minmax(370px,1fr) 370px;background:var(--surface)}
.tg-compose-editor{min-width:0;padding:18px;overflow-y:auto}
.tg-preview-column{min-width:0;padding:18px 16px;overflow-y:auto;border-left:1px solid var(--line);
  background:#d9e7dc;color:#111}
.tg-preview-label{margin-bottom:12px;font-size:10px;font-weight:750;letter-spacing:1px;color:#4c6253}
.tg-post-preview{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif}
.tg-preview-note{margin-top:12px;font-size:10.5px;line-height:1.4;color:#617266}
.tgp-audit{display:grid;gap:3px;margin-bottom:10px;padding:9px 10px;border:1px solid #d9b65d;
  border-radius:9px;background:#fff4cf;color:#705700;font-size:11px;line-height:1.35}
.tgp-audit.bad{border-color:#dc8a8a;background:#ffe4e4;color:#8a2525}.tgp-audit span{display:block}
.tgp-head{display:flex;align-items:center;gap:9px;margin-bottom:8px;padding:0 5px}
.tgp-head>div{display:grid}.tgp-head b{font-size:13px}.tgp-head small{font-size:10px;color:#607066}
.tgp-avatar{display:grid;place-items:center;width:34px;height:34px;border-radius:50%;background:#4f9c6d;
  color:#fff;font-weight:750}
.tgp-message{overflow:hidden;border-radius:12px 12px 5px 12px;background:#fff;
  box-shadow:0 1px 2px rgba(22,47,31,.14)}
.tgp-media{position:relative;overflow:hidden;background:#d2d8d3}
/* Одиночное фото Telegram не режет — он вписывает его целиком, уменьшая
   по размеру бабла. Поэтому у единственного кадра пропорции сохраняем:
   фиксированная высота с cover срезала верх и низ и показывала вертикальный
   кадр без головы, из-за чего казалось, что пост уйдёт таким. */
.tgp-media.n1>img,.tgp-media.n1 .tgp-video>img{display:block;width:100%;height:auto;
  max-height:440px;object-fit:contain}
/* Альбом — мозаика без дырок: клетки расставлены долями, их считает
   tgAlbumRects в app.js. Отступ в пиксель с каждой стороны даёт те же
   двухпиксельные швы, что и в канале. */
.tgp-media.album{display:block}
.tgp-cell{position:absolute;padding:1px;box-sizing:border-box}
.tgp-cell>img,.tgp-cell>.tgp-video,.tgp-cell>.tgp-audio,.tgp-cell>.tgp-file{
  display:block;width:100%;height:100%;min-height:0;box-sizing:border-box}
.tgp-cell>img,.tgp-cell .tgp-video>img{object-fit:cover;height:100%}
.tgp-video{position:relative;display:grid;place-items:center;min-height:150px;background:#25332a;color:#fff}
.tgp-video>img{display:block;width:100%;height:230px;object-fit:cover}
.tgp-video>i{position:absolute;display:grid;place-items:center;width:42px;height:42px;border-radius:50%;
  background:rgba(0,0,0,.5);color:#fff;font-style:normal;padding-left:3px}
.tgp-circle{position:relative;display:grid;place-items:center;width:245px;height:245px;margin:12px auto;
  overflow:hidden;border-radius:50%;background:#25332a;color:#fff}
.tgp-circle img{width:100%;height:100%;object-fit:cover}.tgp-circle i{position:absolute;display:grid;place-items:center;
  width:44px;height:44px;border-radius:50%;background:rgba(0,0,0,.5);color:#fff;font-style:normal;padding-left:3px}
.tgp-audio,.tgp-file{display:flex;align-items:center;gap:9px;min-height:64px;padding:12px;background:#f5f7f5}
.tgp-media.spoiler>*:not(b){filter:blur(18px)}
.tgp-media.spoiler>b{position:absolute;z-index:2;left:50%;top:50%;transform:translate(-50%,-50%);
  padding:5px 10px;border-radius:20px;background:rgba(0,0,0,.55);color:#fff;font-size:11px}
.tgp-media.paid>*:not(.tgp-paid-lock){filter:blur(20px);opacity:.55}.tgp-media .tgp-paid-lock{position:absolute;
  z-index:3;left:50%;top:50%;transform:translate(-50%,-50%);padding:8px 12px;border-radius:18px;
  background:rgba(33,28,6,.78);color:#fff;font-size:11px;white-space:nowrap}
.tgp-text{padding:9px 11px 4px;font-size:13px;line-height:1.35;white-space:normal;overflow-wrap:anywhere}
.tgp-link{color:#1687c2;text-decoration:underline;text-decoration-thickness:.5px}
.tgp-meta{display:flex;justify-content:flex-end;gap:8px;padding:2px 9px 6px;color:#7d8d82;font-size:10px}
.tgp-stars{margin:8px 10px 0;padding:7px 9px;border-radius:8px;background:#f5e8af;color:#705b00;
  font-size:11px;font-weight:650;text-align:center}
.tgp-buttons{display:grid;gap:3px;margin-top:3px}
.tgp-buttons>div{position:relative;padding:9px 28px;border-radius:7px;background:rgba(255,255,255,.62);
  color:#1687c2;text-align:center;font-size:12px;font-weight:650;box-shadow:0 1px 1px rgba(22,47,31,.08)}
.tgp-buttons>div.primary{background:#3aa5dc;color:#fff}.tgp-buttons>div.success{background:#49a95d;color:#fff}
.tgp-buttons>div.danger{background:#d65b5b;color:#fff}
.tgp-buttons>div span{position:absolute;right:10px}.tgp-reaction{display:inline-block;margin-top:5px;padding:3px 8px;
  border-radius:14px;background:rgba(255,255,255,.74);font-size:12px}.tgp-action-note{margin-top:8px;
  padding:6px 8px;border-radius:7px;background:rgba(255,255,255,.5);font-size:10.5px;color:#617266}
.tgp-poll{padding:12px 11px 6px}.tgp-poll>b{display:block;margin-bottom:9px;font-size:13px}
.tgp-poll>div{display:flex;align-items:center;gap:8px;margin:7px 0;font-size:12px}
.tgp-poll>div i{width:15px;height:15px;border:1.5px solid #2799d0;border-radius:50%}
.tgp-poll>small{display:block;margin-top:9px;color:#7d8d82;font-size:10px}
@media (max-width:820px){
  .drawer.tg-compose-open{width:100%;max-width:100%;display:block;overflow-y:auto}
  .tg-compose-editor{overflow:visible}
  .tg-preview-column{border-left:0;border-top:1px solid var(--line)}
}

/* Поле времени: цифры моноширинными, чтобы «11:05» и «22:50» не прыгали
   по ширине при наборе. Узкое — в нём всегда ровно пять знаков. */
.tfield{max-width:130px;font-variant-numeric:tabular-nums;letter-spacing:.5px}

/* Выбор нескольких типов для календаря. Своя панель, а не <select multiple>:
   тот показывает список простынёй и требует держать Ctrl, чего в списке
   из десятка типов никто не угадает. */
.mselect{position:relative;display:inline-block}
.msbtn{padding:6px 12px;border:1px solid var(--line);border-radius:9px;background:var(--surface);
  color:var(--txt);font-size:var(--fs-sm);cursor:pointer;min-width:170px;text-align:left}
.msbtn::after{content:'▾';float:right;color:var(--muted);margin-left:8px}
.msbtn.on{border-color:var(--accent);color:var(--accent);font-weight:600}
.mspanel{position:absolute;z-index:40;top:calc(100% + 4px);left:0;min-width:230px;max-height:340px;
  overflow-y:auto;padding:5px;border:1px solid var(--line);border-radius:10px;
  background:var(--surface);box-shadow:0 10px 28px rgba(0,0,0,.16)}
.mspanel .msall{width:100%;text-align:left;padding:6px 8px;border:0;border-radius:7px;
  background:transparent;color:var(--accent);font-size:var(--fs-sm);cursor:pointer}
.mspanel .msall:disabled{color:var(--muted);cursor:default}
.mspanel .msall:not(:disabled):hover{background:var(--surface2)}
.msrow{display:flex;align-items:center;gap:7px;margin:0;padding:5px 8px;border-radius:7px;
  font-size:var(--fs-sm);cursor:pointer;white-space:nowrap}
.msrow:hover{background:var(--surface2)}
.msrow input{width:auto;margin:0;flex:0 0 auto}
.msrow.msplatform{margin-top:4px;font-weight:650;color:var(--txt)}
.msrow.mschild{padding-left:28px}
.msrow .pf{display:flex;align-items:center;flex:0 0 auto}
.msrow .pf :is(svg,.pfimg){width:15px;height:15px;display:block;object-fit:contain}
.msrow .pfm{display:grid;place-items:center;width:15px;height:15px;font-size:9px;font-style:normal;
  font-weight:800;line-height:1;border:1.5px solid currentColor;border-radius:4px}

/* В системных option нельзя вставить SVG, поэтому фильтр банка использует
   собственную панель, но оставляет прежнее одиночное значение и группировку. */
.bank-type-select .msbtn{display:flex;align-items:center;min-width:240px;max-width:320px}
.bank-type-select .msbtn::after{float:none;margin-left:auto}
.bank-type-label,.bank-type-option,.bank-type-group{display:flex;align-items:center;gap:7px}
.bank-type-label{min-width:0}
.bank-type-label>span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bank-type-select .mspanel{min-width:310px}
.bank-type-option{width:100%;padding:6px 8px;border:0;border-radius:7px;background:transparent;
  color:var(--txt);font-size:var(--fs-sm);text-align:left;cursor:pointer;white-space:nowrap}
.bank-type-option:hover,.bank-type-option.active{background:var(--surface2)}
.bank-type-option.active{color:var(--accent);font-weight:600}
.bank-type-group{padding:9px 8px 3px;color:var(--txt);font-size:var(--fs-sm)}
.bank-type-select .pf{display:flex;align-items:center;flex:0 0 auto}
.bank-type-select .pf :is(svg,.pfimg){width:15px;height:15px;display:block;object-fit:contain}
.bank-type-select .pfm{display:grid;place-items:center;width:15px;height:15px;font-size:9px;
  font-style:normal;font-weight:800;line-height:1;border:1.5px solid currentColor;border-radius:4px}

/* Таблица типов: площадка своей колонкой со значком, как в календаре. */
.tplat{white-space:nowrap}
.tplat .pf{display:inline-flex;align-items:center;vertical-align:-3px;margin-right:6px}
.tplat .pf :is(svg,.pfimg){width:16px;height:16px;display:block;object-fit:contain}
.tplat .pfm{display:inline-grid;place-items:center;width:16px;height:16px;font-size:10px;
  font-style:normal;font-weight:800;line-height:1;border:1.5px solid currentColor;border-radius:4px}

/* Заголовки-сортировщики. Стрелка держит своё место всегда, иначе строка
   заголовков дёргается по ширине при каждом переключении. */
#normsTable th.sortable{cursor:pointer;user-select:none}
#normsTable th.sortable:hover{color:var(--txt)}
#normsTable .sarr{display:inline-block;width:12px;margin-left:3px;font-size:9px;
  color:var(--accent);vertical-align:1px}
#normsTable .sarr:not(.on){opacity:0}
#normsTable th.sortable:hover .sarr:not(.on){opacity:.35;color:var(--muted)}
#normsTable th.sortable:hover .sarr:not(.on)::after{content:'▲'}

/* ---------- панель эмодзи ----------
   Используется внутри диалога ввода, когда набирают надпись на кнопке. */
.emoji-pan{margin:6px 0;padding:6px 8px;border:1px solid var(--line);border-radius:10px;
  background:var(--bg);max-height:190px;overflow-y:auto}
.emoji-grp{margin-bottom:4px;line-height:1.9}
.emoji-grp .dim{display:block;font-size:10px;font-weight:750;letter-spacing:.8px;
  text-transform:uppercase}
.emoji-pan .emo{width:30px;height:28px;padding:0;margin:0 1px;border:0;border-radius:6px;
  background:transparent;font-size:17px;line-height:1;cursor:pointer;vertical-align:middle}
.emoji-pan .emo:hover{background:var(--line)}


/* Полировка стоит под результатом: сначала собранное, потом что с ним делать. */
.gen-polish{display:grid;grid-template-columns:112px 112px max-content minmax(190px,360px) minmax(220px,1fr);align-items:end;margin-top:10px;gap:6px}
.gen-polish-limits{font-size:var(--fs-sm);margin-top:10px}
.gen-polish label{width:112px;margin:0;font-size:calc(var(--fs-sm) * .92)}
.gen-polish select{margin:0;padding:5px 24px 5px 8px;font-size:12px}
.gen-polish input{margin:0;padding:5px 8px;font-size:12px}
.gen-polish label input{margin-top:4px}
@media (max-width:1000px){.gen-polish{grid-template-columns:112px 112px max-content 1fr}.gen-polish>#or_model_prompt{grid-column:1/-1}}

/* Свой диалог ввода вместо браузерного prompt. Тот подписан «localhost:8080
   says», игнорирует тему страницы и не даёт ни подсказки, ни списка. z-index
   выше панели: переименовывать приходится и из неё. */
.ask{position:fixed;inset:0;z-index:80;display:none;align-items:center;justify-content:center;
  background:rgba(0,0,0,.4);padding:20px}
.ask.on{display:flex}
.askbox{width:min(420px,100%);background:var(--surface);border:1px solid var(--line);
  border-radius:14px;padding:18px;box-shadow:0 18px 50px rgba(0,0,0,.28)}
.askttl{font-size:calc(var(--fs-big) * .68);font-weight:600;margin-bottom:12px;line-height:1.35}
.askbox input,.askbox select{margin:0}
.askhint{margin-top:8px;font-size:var(--fs-sm);color:var(--dim);white-space:pre-line}
.askrow{justify-content:flex-end;margin-top:16px}

/* Кадр во весь экран по щелчку в карточке. Снимок в панели ужат по её ширине,
   а смотреть надо детали — свет, руки, лишние пальцы. */
.zoomable{cursor:zoom-in}
.lbox{display:none;position:fixed;inset:0;z-index:300;padding:26px;
  align-items:center;justify-content:center;background:rgba(14,11,12,.88)}
.lbox.on{display:flex}
.lbox img{max-width:100%;max-height:100%;width:auto;height:auto;border-radius:8px;
  box-shadow:0 24px 64px rgba(0,0,0,.55);cursor:zoom-out}
.lbox-x{position:absolute;top:14px;right:16px;width:34px;height:34px;padding:0;border-radius:99px;
  border:none;background:rgba(255,255,255,.14);color:#fff;font-size:15px;line-height:1;cursor:pointer}
.lbox-x:hover{background:rgba(255,255,255,.26)}
.lbox-nav{position:absolute;top:50%;left:14px;transform:translateY(-50%);
  width:42px;height:60px;padding:0;border:none;border-radius:12px;
  background:rgba(255,255,255,.12);color:#fff;font-size:28px;line-height:1;cursor:pointer}
.lbox-nav.next{left:auto;right:14px}
.lbox-nav:hover{background:rgba(255,255,255,.24)}
.lbox-cap{position:absolute;left:0;right:0;bottom:10px;text-align:center;
  color:#ece5e7;font-size:12px;font-variant-numeric:tabular-nums;pointer-events:none}

/* ---------- Вход ----------
   Полноэкранный слой поверх всего: приложение за ним не грузится, пока
   нет сессии. Показывается только на сервере с заданным APP_PASSWORD. */
#gate{position:fixed;inset:0;z-index:9999;display:flex;align-items:center;
  justify-content:center;background:var(--bg);padding:20px}
#gate form{width:100%;max-width:320px;display:flex;flex-direction:column;gap:10px}
#gate h1{margin:0 0 6px;font-size:20px;font-weight:600}
#gate label{font-size:var(--fs-sm);color:var(--dim)}
#gate input{width:100%;font-size:16px}          /* 16px — иначе iOS зумит поле */
#gate button{background:var(--accent);border-color:var(--accent);color:#fff;padding:10px}
#gate button[disabled]{opacity:.6;cursor:default}
#gateErr{min-height:18px;font-size:var(--fs-sm);color:var(--bad)}
