/* RFP Tracker — дашборд v2. Єдиний стиль-файл.
   Розділ 3 специфікації. Зовнішніх ресурсів немає: ні імпортів, ні посилань
   на чужі хости — CSP `style-src 'self'` має проходити без винятків.
   Тема одна — темна (3.9): світлу свідомо не робимо, але всі кольори
   лежать у токенах, тож пізніше це один блок @media, без правок розмітки. */

/* ─────────────────────────────  1. Токени  ───────────────────────────── */

:root{
  color-scheme: dark;

  /* Бренд — рівно два кольори з лого */
  --brand-1:#10B981; --brand-2:#06B6D4;
  --brand-grad:linear-gradient(135deg,var(--brand-1) 0%,var(--brand-2) 100%);
  --brand-ink:#05201A;              /* текст ПОВЕРХ градієнта (6.7:1 і 7.0:1) */

  /* Поверхні — холодний сланець, зсунутий у бік бренду */
  --bg:#0B1014; --surface:#111A21; --surface-2:#16222B; --input:#1B2833;
  --line:#20303A; --line-soft:#1A272F;

  /* Текст */
  --text:#E6EDF3; --text-dim:#93A4B1; --text-faint:#647685;

  /* Семантика — приглушені, НЕ бренд-хроми (див. 3.3) */
  --ok:#2FA37A;   --ok-bg:#0E2B23;
  --warn:#F0B429; --warn-bg:#2E2411;
  --bad:#F0616D;  --bad-bg:#2E1519;
  --info:#06B6D4; --info-bg:#0B2830;
  --neutral:#7C8B99; --neutral-bg:#1A242C;
  --focus:#22D3EE;

  /* Геометрія */
  --r-sm:6px; --r-md:10px; --r-lg:14px; --r-pill:999px;
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:24px; --sp-6:32px;
  --sidebar-w:236px; --topbar-h:60px; --content-max:1440px;
  --sh-1:0 1px 2px rgb(0 0 0/.4); --sh-2:0 12px 32px -8px rgb(0 0 0/.55);

  /* Типографіка. "Noto Sans"/"Liberation Sans" — щоб український текст на
     Linux-браузерах не падав на дефолтний sans із гіршим хінтингом. */
  --font:ui-sans-serif,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",
         "Noto Sans","Liberation Sans",Arial,sans-serif;
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,
         "Liberation Mono","DejaVu Sans Mono",monospace;
  --fs-xs:11.5px; --fs-sm:12.5px; --fs-md:14px; --fs-lg:16px;
  --fs-xl:20px; --fs-2xl:28px;
  --lh-tight:1.25; --lh:1.55;

  /* Аліаси старих імен зі знесеного <style> у base.html. Потрібні рівно доти,
     доки в шаблонах лишаються інлайнові style="…: var(--panel)" (brief.html).
     Крок 3 їх вичищає — тоді цей блок видаляється. */
  --panel:var(--surface); --border:var(--line); --muted:var(--text-dim);
  --accent:var(--info); --seed:var(--neutral);
}

/* ──────────────────────────  2. Базовий шар  ─────────────────────────── */

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0; background:var(--bg); color:var(--text);
  font-family:var(--font); font-size:var(--fs-md); line-height:var(--lh);
  -webkit-font-smoothing:antialiased;
}
[hidden]{display:none !important}

h1,h2,h3,h4{margin:0; line-height:var(--lh-tight); font-weight:600}
h1{font-size:var(--fs-xl)}
/* 3.5: жодного text-transform:uppercase — кириличний капс читається гірше */
h2{font-size:var(--fs-lg)}
h3{font-size:var(--fs-md)}
p{margin:0 0 var(--sp-3)}
p:last-child{margin-bottom:0}
ul,ol{margin:0 0 var(--sp-3); padding-left:1.25em}

a{color:var(--brand-2); text-decoration:none}
a:hover{text-decoration:underline}

hr{border:0; border-top:1px solid var(--line); margin:var(--sp-4) 0}

code,kbd,samp{font-family:var(--mono); font-size:var(--fs-sm)}
code{background:var(--bg); border:1px solid var(--line-soft);
     padding:1px 5px; border-radius:var(--r-sm)}
pre{margin:0; font-family:var(--mono); font-size:var(--fs-sm); overflow-x:auto}

img,svg{max-width:100%}
.mono{font-family:var(--mono)}
.num,.stat__num{font-variant-numeric:tabular-nums}

/* ────────────────────────  3. Доступність (3.8)  ─────────────────────── */

:where(a,button,input,select,textarea,summary,label):focus-visible{
  outline:2px solid var(--focus); outline-offset:2px; border-radius:var(--r-sm);
}
@media (prefers-reduced-motion:reduce){
  *,::before,::after{animation-duration:.01ms !important; transition-duration:.01ms !important}
}
.skip{position:absolute; left:-9999px}
.skip:focus{
  left:var(--sp-2); top:var(--sp-2); z-index:100;
  padding:var(--sp-2) var(--sp-3); background:var(--surface-2);
  border:1px solid var(--line); border-radius:var(--r-sm); color:var(--text);
}
.visually-hidden{
  position:absolute; width:1px; height:1px; overflow:hidden;
  clip-path:inset(50%); white-space:nowrap;
}

/* ─────────────────────────  4. Сітка (2.4)  ──────────────────────────── */

/* minmax(0,1fr) — не косметика: без нього широка таблиця розпирає grid-трек
   і горизонтальний скрол з'їжджає на <body> замість .tablewrap. */
.app{display:grid; grid-template-columns:var(--sidebar-w) minmax(0,1fr); min-height:100dvh}

.sidebar{
  position:sticky; top:0; height:100dvh; display:flex; flex-direction:column;
  overflow-y:auto; background:var(--surface); border-right:1px solid var(--line);
}
.shell{display:flex; flex-direction:column; min-width:0}

.topbar{
  position:sticky; top:0; z-index:20; height:var(--topbar-h);
  display:flex; align-items:center; gap:var(--sp-4); padding:0 var(--sp-5);
  background:var(--bg);
  background:color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter:blur(8px); border-bottom:1px solid var(--line);
}
.topbar__burger{display:none; align-items:center; justify-content:center;
  width:34px; height:34px; margin-left:calc(-1 * var(--sp-2));
  border:1px solid var(--line); border-radius:var(--r-md);
  background:var(--surface-2); cursor:pointer; font-size:var(--fs-lg)}
.topbar__title{min-width:0; flex:1 1 auto}
.topbar__title h1{font-size:var(--fs-lg); white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis}
.topbar__sub{margin:0; font-size:var(--fs-sm); color:var(--text-dim);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.topbar__meta{display:flex; align-items:center; gap:var(--sp-2); flex:0 0 auto}

.content{padding:var(--sp-5); max-width:var(--content-max); width:100%}
.controls{margin-bottom:var(--sp-5)}
.data > * + *{margin-top:var(--sp-5)}

/* ────────────────  5. Сайдбар: марка, навігація, підвал  ─────────────── */

.brand{
  display:flex; align-items:center; gap:var(--sp-2);
  padding:var(--sp-4) var(--sp-4) var(--sp-3);
  color:var(--text); text-decoration:none; font-weight:700; font-size:var(--fs-lg);
}
.brand:hover{text-decoration:none}
.brand__mark{flex:0 0 auto}
.brand__name{white-space:nowrap}

.nav{flex:1; padding:var(--sp-2)}
.nav__group{
  margin:var(--sp-4) 0 var(--sp-1); padding:0 var(--sp-3);
  font-size:var(--fs-xs); font-weight:600; letter-spacing:.01em; color:var(--text-dim);
}
.nav__group:first-child{margin-top:var(--sp-1)}
.nav__item{
  display:flex; align-items:center; gap:var(--sp-2);
  padding:7px var(--sp-3); margin-bottom:2px;
  border-radius:var(--r-md); color:var(--text-dim); text-decoration:none;
  font-size:var(--fs-md); line-height:1.35;
}
.nav__item:hover{background:var(--surface-2); color:var(--text); text-decoration:none}
.nav__item.is-active{background:var(--surface-2); color:var(--text); font-weight:600;
  box-shadow:inset 2px 0 0 0 var(--brand-1)}
.nav__item--ext{color:var(--text-faint)}
.nav__item .badge{margin-left:auto}

.sidebar__foot{border-top:1px solid var(--line); padding:var(--sp-3); margin-top:auto}

.session{
  display:flex; align-items:center; gap:var(--sp-2); margin-bottom:var(--sp-2);
  font-size:var(--fs-sm); color:var(--text-dim); font-variant-numeric:tabular-nums;
}
.session__dot{width:7px; height:7px; border-radius:50%; background:var(--ok); flex:0 0 auto}
.session.is-warn{color:var(--warn)}
.session.is-warn .session__dot{background:var(--warn)}

/* Банер «сесія завершується» — DOM створює app.js, тож без JS його просто нема */
.session-banner{
  position:fixed; left:50%; bottom:var(--sp-5); transform:translateX(-50%); z-index:60;
  display:flex; align-items:center; gap:var(--sp-3);
  max-width:calc(100vw - 2 * var(--sp-4));
  padding:10px var(--sp-4);
  background:var(--surface-2); border:1px solid var(--warn); border-radius:var(--r-pill);
  box-shadow:var(--sh-2); font-size:var(--fs-md);
}
.session-banner__val{font-variant-numeric:tabular-nums; font-weight:600; color:var(--warn)}

/* ──────────────────  6. Мобільний off-canvas (2.5)  ──────────────────── */

.scrim{display:none}

@media (max-width:900px){
  .app{grid-template-columns:1fr}
  .sidebar{
    position:fixed; z-index:40; width:var(--sidebar-w);
    transform:translateX(-100%); transition:transform .18s;
  }
  #nav-toggle:checked ~ .sidebar{transform:none}
  #nav-toggle:checked ~ .scrim{display:block}
  .scrim{position:fixed; inset:0; z-index:30; background:rgb(0 0 0/.55)}
  .topbar__burger{display:inline-flex}
  .content{padding:var(--sp-4)}
  .topbar{padding:0 var(--sp-4); gap:var(--sp-3)}
}
@media (min-width:901px){
  .topbar__burger,.scrim{display:none}
}

/* ─────────────────  7. Заділ під AI-чат і правий рейл (2.6)  ─────────── */

/* min-height:0 на КОЖНОМУ flex-предку обов'язковий — інакше стрічка не
   скролиться всередині, а розтягує сторінку. Padding з .data знятий свідомо
   (розділ 1 редизайну чату) — тепер його розподіляють .chat-col/.chat-side
   нижче, кожен по-своєму, а .data лише тримає висоту й ховає переповнення
   між ними (свій скрол — усередині .chat-col__scroll і .chat-side). */
.content--full{
  display:flex; flex-direction:column; height:calc(100dvh - var(--topbar-h));
  max-width:none; padding:0; overflow:hidden;
}
.content--full .data{flex:1; min-height:0; overflow:hidden; padding:0}

/* D1: приклади питань на порожньому стані чату — вертикальний стовпчик
   повноширинних ghost-кнопок під .empty вище, а не .chips (той пасує
   коротким лейблам, тут — цілі речення). */
.chat__examples{
  display:flex; flex-direction:column; gap:var(--sp-2);
  max-width:520px; margin:var(--sp-5) auto 0;
}
.chat__examples .btn{text-align:left}

.with-rail{display:flex; align-items:flex-start; gap:var(--sp-5)}
.with-rail > *:first-child{flex:1 1 auto; min-width:0}
.rail{
  flex:0 0 280px; width:280px;
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-lg); padding:var(--sp-4); font-size:var(--fs-sm);
}
@media (max-width:1100px){
  .with-rail{flex-direction:column}
  .rail{flex:1 1 auto; width:100%}
}

/* ────────────────────────  8. Кнопки і поля  ─────────────────────────── */

.btn,button{
  display:inline-flex; align-items:center; justify-content:center; gap:var(--sp-2);
  padding:7px 14px; border:1px solid var(--line); border-radius:var(--r-md);
  background:var(--surface-2); color:var(--text);
  font:inherit; font-size:var(--fs-md); font-weight:500; line-height:1.3;
  text-decoration:none; cursor:pointer;
  transition:background .15s, border-color .15s, filter .15s;
}
.btn:hover,button:hover{background:var(--input); border-color:#2C4150; text-decoration:none}
/* 3.3: насичений градієнт — рівно двічі на екран (марка + одна головна дія) */
.btn--primary{background:var(--brand-grad); color:var(--brand-ink);
  border-color:transparent; font-weight:600}
.btn--primary:hover{background:var(--brand-grad); filter:brightness(1.07)}
.btn--ghost{background:transparent}
.btn--ghost:hover{background:var(--surface-2)}
.btn--danger{color:var(--bad); border-color:var(--bad-bg); background:var(--bad-bg)}
/* Зелений близнюк .btn--danger — для позитивних оцінок (Useful на /items):
   та сама семантична пара, що й .b-ok/.alert--ok, жодних нових кольорів. */
.btn--ok{color:var(--ok); border-color:var(--ok-bg); background:var(--ok-bg)}
.btn--ok:hover{background:var(--ok-bg); border-color:var(--ok)}
.btn--danger:hover{background:var(--bad-bg); border-color:var(--bad)}
.btn--sm,button.small{padding:2px 10px; font-size:var(--fs-sm)}
.btn--block{width:100%}
.btn[disabled],button[disabled],.btn:disabled,button:disabled{
  opacity:.55; cursor:not-allowed; filter:none;
}
.btn--link{background:none; border:0; padding:0; color:var(--brand-2)}
.btn--link:hover{background:none; text-decoration:underline}

input:not([type=checkbox]):not([type=radio]),select,textarea,.input{
  font:inherit; font-size:var(--fs-md); color:var(--text);
  background:var(--input); border:1px solid var(--line); border-radius:var(--r-md);
  padding:7px 10px; min-width:0; max-width:100%;
}
textarea{font-family:var(--mono); font-size:var(--fs-sm); min-height:90px; resize:vertical}
input::placeholder,textarea::placeholder{color:var(--text-faint)}
input:hover,select:hover,textarea:hover{border-color:#2C4150}
select{cursor:pointer}
label{cursor:pointer}
.input--wide{width:100%}
.check{display:inline-flex; align-items:center; gap:var(--sp-2); font-size:var(--fs-sm);
  color:var(--text-dim)}

/* /sources «Discover» (задача «менше ручного JSON») — знайдені discourse-
   категорії як чекбокси замість JSON вручну. .cfg-discovered — прокручувана
   колонка (форуми на кшталт Optimism віддають десятки категорій разом із
   підкатегоріями); .check--indent зсуває підкатегорію під її батька, той
   самий відступ, що й у списках меню (розділ 9, .menu__group). */
.cfg-discovered{display:flex; flex-direction:column; gap:var(--sp-1);
  max-height:260px; overflow-y:auto; padding:var(--sp-2);
  border:1px solid var(--line); border-radius:var(--r-md)}
.check--indent{margin-left:var(--sp-5)}

/* Форма «Додати джерело» = три кроки згори вниз (прохання власника
   2026-08-12: кнопки мають стояти органічно, config — допоміжне).
   .form-step — нумерований підзаголовок кроку; .url-row — поле URL і
   кнопка-помічник В ОДНОМУ рядку (кнопка як продовження дії «вставив
   адресу», а не окремий розділ під нею); .disclosure--sub — вкладений
   <details> «Advanced» без власної рамки, щоб не виглядав як друга
   панель усередині вже відкритої форми. */
.form-step{margin:var(--sp-4) 0 var(--sp-2); font-size:var(--fs-sm);
  font-weight:600; color:var(--text)}
.form-step:first-of-type{margin-top:0}
.form-step__hint{margin:var(--sp-2) 0 0}
.url-row{display:flex; gap:var(--sp-3); align-items:flex-start; flex-wrap:wrap}
.url-row__input{flex:1 1 320px}
.url-row--discover{align-items:center; margin-top:var(--sp-3)}
.disclosure--sub{margin-top:var(--sp-4); background:none; border-color:var(--line-soft)}
.disclosure--sub > summary{font-weight:500; color:var(--text-dim)}
.disclosure--sub .disclosure__body{padding-top:var(--sp-3)}

.field{display:flex; flex-direction:column; gap:var(--sp-1); min-width:0}
.field--wide{grid-column:1 / -1}
.field__label{font-size:var(--fs-sm); font-weight:600; color:var(--text-dim)}
.field__hint{font-size:var(--fs-sm); color:var(--text-dim)}
.field__hint--bad{color:var(--bad)}

.form-grid{display:grid; grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  gap:var(--sp-3) var(--sp-4)}

.toolbar{display:flex; flex-wrap:wrap; align-items:flex-end; gap:var(--sp-3)}
.toolbar__spacer{flex:1 1 auto}
.toolbar + .toolbar,.toolbar + .disclosure,.toolbar + details{margin-top:var(--sp-3)}

/* ─────────────────────────  9. Компоненти  ───────────────────────────── */

/* Пігулки. Базовий .badge нейтральний, варіанти лише перевизначають дві
   змінні — новий статус із БД не стане невидимим. */
.badge{
  display:inline-flex; align-items:center; gap:var(--sp-1);
  padding:1px 8px; border-radius:var(--r-pill);
  font-size:var(--fs-xs); font-weight:600; line-height:1.7; white-space:nowrap;
  color:var(--pill-fg,var(--neutral)); background:var(--pill-bg,var(--neutral-bg));
}
.b-done,.b-on,.b-ok{--pill-fg:var(--ok); --pill-bg:var(--ok-bg)}
.b-pending,.b-warn{--pill-fg:var(--warn); --pill-bg:var(--warn-bg)}
.b-dead,.b-bad,.b-quarantine{--pill-fg:var(--bad); --pill-bg:var(--bad-bg)}
.b-rfp,.b-info{--pill-fg:var(--info); --pill-bg:var(--info-bg)}
.b-seeded,.b-filtered,.b-off,.b-soon,.b-neutral{--pill-fg:var(--neutral); --pill-bg:var(--neutral-bg)}
.b-funding{--pill-fg:#C79BE8; --pill-bg:#241833}
/* Розділ B1/B2: чип «LEAD»/бейдж NAV — прив'язаний до брендового акценту
   (--brand-1), а не до семантичних --ok/--warn/--bad вище: «лід» тут не
   статус (won/lost — те, вже покриває --ok/--bad на цій сторінці), а
   окрема, наскрізна для всього дашборда категорія уваги, тому й колір —
   той самий, що й акцентна рамка .item-row--lead нижче. */
.b-lead{--pill-fg:var(--brand-1); --pill-bg:color-mix(in srgb, var(--brand-1) 18%, var(--surface-2))}

.alert{
  padding:10px 14px; margin-bottom:var(--sp-4);
  border:1px solid transparent; border-radius:var(--r-md); font-size:var(--fs-md);
}
.alert:last-child{margin-bottom:0}
.alert--ok{color:var(--ok); background:var(--ok-bg); border-color:#17402F}
.alert--err{color:var(--bad); background:var(--bad-bg); border-color:#4A2229}
.alert--info{color:var(--info); background:var(--info-bg); border-color:#0F3A45}

.panel{background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-lg); overflow:hidden}
.panel__head{
  display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-3);
  padding:var(--sp-3) var(--sp-4); border-bottom:1px solid var(--line-soft);
}
.panel__head > h2,.panel__head > h3,.panel__title{font-size:var(--fs-md); font-weight:600}
.panel__head .toolbar__spacer{flex:1 1 auto}
.panel__body{padding:var(--sp-4)}
.panel__body--flush{padding:0}
.panel__foot{
  padding:var(--sp-3) var(--sp-4); border-top:1px solid var(--line-soft);
  background:var(--surface-2); font-size:var(--fs-sm); color:var(--text-dim);
}
.panels{display:grid; gap:var(--sp-5)}
@media (min-width:1200px){
  .panels--2{grid-template-columns:repeat(2,minmax(0,1fr))}
}

.stats{display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:var(--sp-3)}
.stat{
  display:block; padding:var(--sp-4);
  background:var(--surface); border:1px solid var(--line); border-radius:var(--r-lg);
  color:inherit; text-decoration:none;
}
a.stat:hover{border-color:var(--brand-1); text-decoration:none}
.stat__num{font-size:var(--fs-2xl); font-weight:700; line-height:1.1}
.stat__lbl{margin-top:2px; font-size:var(--fs-sm); color:var(--text-dim)}
/* Розділ B3: плитка «Нові ліди (24 год)» — та сама пара --brand-1, що й
   .b-lead/.item-row--lead нижче, щоб три місця («NAV-бейдж», «рядок
   знахідки», «плитка Огляду»), які показують одне й те саме число, читалися
   як одна візуальна категорія. */
.stat--lead{border-color:var(--brand-1)}
.stat--lead .stat__num{color:var(--brand-1)}

/* 3.7: sticky thead свідомо немає — overflow-x:auto і position:sticky
   взаємно виключні. Обгортка обов'язкова для КОЖНОЇ таблиці. */
.tablewrap{overflow-x:auto; -webkit-overflow-scrolling:touch}
.panel > .tablewrap{border-radius:0}

table,.table{width:100%; border-collapse:collapse; font-size:var(--fs-md)}
table{background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-lg); overflow:hidden}
.panel table,.tablewrap > table{border:0; border-radius:0; background:none}
th,td{padding:9px 12px; text-align:left; vertical-align:top;
  border-bottom:1px solid var(--line-soft)}
td{font-variant-numeric:tabular-nums}
th{color:var(--text-dim); font-weight:600; font-size:var(--fs-sm);
  letter-spacing:.01em; white-space:nowrap}
tbody tr:last-child td{border-bottom:none}
tbody tr:hover{background:var(--surface-2)}
/* 6px, не 10px: прохання Миколи 2026-08-12 — вужчі відступи між
   стовпчиками, щоб колонка дій ([select][brief][Ask AI]) трималась ОДНИМ
   рядком без переносів і без горизонтального скролу (7 колонок × 2 боки ×
   4px = 56px виграшу). */
.table--dense th,.table--dense td{padding:5px 6px; font-size:var(--fs-sm)}
.cell--num{text-align:right}
.cell--nowrap{white-space:nowrap}

/* Розділ B1: рядок-лід на /items (items.html: delivered_at IS NOT NULL) —
   акцентна ліва рамка + ледь помітний фон, обидва виведені з --brand-1, а
   не захардкоджені кольори: якщо колись з'явиться друга тема поверх наявних
   custom properties (файл поки свідомо однотемний, розділ 1), підсвітка
   переїде сама, без правок розмітки. `:hover` окремим правилом — інакше
   загальний `tbody tr:hover` вище (нижча специфічність, але йде пізніше
   каскадом) перебив би підсвічений фон при наведенні. */
.item-row--lead{
  box-shadow:inset 3px 0 0 0 var(--brand-1);
  background:color-mix(in srgb, var(--brand-1) 7%, transparent);
}
.item-row--lead:hover{background:color-mix(in srgb, var(--brand-1) 13%, transparent)}

.chips{display:flex; flex-wrap:wrap; gap:var(--sp-2)}
.chip{
  padding:4px 12px; border:1px solid var(--line); border-radius:var(--r-pill);
  background:var(--surface); color:var(--text-dim);
  font-size:var(--fs-sm); text-decoration:none; cursor:pointer;
}
.chip:hover{color:var(--text); text-decoration:none}
.chip[aria-current="true"],.chip.is-active{
  background:var(--surface-2); color:var(--text); border-color:var(--brand-1);
}

.empty{padding:var(--sp-6) var(--sp-4); text-align:center; color:var(--text-dim)}
.empty__title{margin-bottom:var(--sp-2); font-size:var(--fs-lg); font-weight:600; color:var(--text)}
.empty__hint{font-size:var(--fs-sm)}

/* Спливаюче ⋯-меню (розділ 2 редизайну AI-чату — перший споживач, компонент
   генеричний і піде по всій платформі надалі). `<details class="menu">` —
   без жодного JS відкривається/закривається кліком по summary; app.js
   (розділ «Спливаючі ⋯-меню») лише додає закриття по кліку поза меню й по
   Escape та ексклюзивність (відкриття одного закриває решту) — без JS
   поведінка лишається коректною, просто менш зручною.
     <details class="menu">
       <summary class="menu__btn">⋯</summary>
       <div class="menu__list"> …menu__item… </div>
     </details>
   `list-style:none` + приховування власного трикутника Chrome/Firefox —
   меню не повинно виглядати як звичайний <details>.disclosure вище. */
.menu{position:relative; display:inline-block}
.menu__btn{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:30px; padding:4px 8px; border:1px solid var(--line);
  border-radius:var(--r-md); background:var(--surface-2); color:var(--text-dim);
  font-size:var(--fs-md); line-height:1; cursor:pointer; list-style:none;
}
.menu__btn::-webkit-details-marker{display:none}
.menu__btn:hover{background:var(--input); color:var(--text)}
.menu[open] > .menu__btn{color:var(--text); border-color:#2C4150}
.menu__list{
  position:absolute; right:0; top:calc(100% + 4px); z-index:50;
  min-width:220px; padding:4px;
  background:var(--surface-2); border:1px solid var(--line);
  border-radius:var(--r-md); box-shadow:var(--sh-2);
}
/* .menu--up — для композера внизу колонки: вниз меню розкриватись нікуди. */
.menu--up > .menu__list{top:auto; bottom:calc(100% + 4px)}
.menu__group{
  margin:var(--sp-2) var(--sp-2) 2px; padding-top:var(--sp-1);
  border-top:1px solid var(--line-soft);
  font-size:var(--fs-xs); font-weight:600; color:var(--text-dim);
}
.menu__group:first-child{margin-top:0; padding-top:0; border-top:0}
.menu__hint{margin:2px var(--sp-2) var(--sp-2); font-size:var(--fs-xs); color:var(--text-dim); max-width:26ch}
/* menu__item — і посилання/кнопки, і форми (обгортка навколо кнопки) мусять
   виглядати однаково: повноширинні, ліворуч, без рамки кнопки за замовчуванням. */
.menu__item-form{display:block}
a.menu__item,button.menu__item{
  display:flex; width:100%; align-items:center; gap:var(--sp-2);
  padding:6px 8px; border:0; border-radius:var(--r-sm);
  background:none; color:var(--text); font:inherit; font-size:var(--fs-sm);
  text-align:left; text-decoration:none; cursor:pointer; white-space:nowrap;
}
a.menu__item:hover,button.menu__item:hover{background:var(--input); text-decoration:none}
.menu__item--danger{color:var(--bad)}
.menu__item--danger:hover{background:var(--bad-bg)}
.menu__item--check{cursor:pointer; font-weight:400}
.menu__item--check input{margin-right:2px}

details.disclosure{background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-lg)}
details.disclosure > summary{
  display:flex; align-items:center; gap:var(--sp-2);
  padding:10px var(--sp-4); font-weight:600; cursor:pointer; list-style:none;
}
details.disclosure > summary::-webkit-details-marker{display:none}
details.disclosure > summary::before{
  content:"\25B8"; display:inline-block; color:var(--text-dim); transition:transform .15s;
}
details.disclosure[open] > summary::before{transform:rotate(90deg)}
.disclosure__body{padding:0 var(--sp-4) var(--sp-4)}

/* Задача 2 п.4 аудиту (/runs): список помилок одного прогону в комірці
   таблиці — інакше десятки провалених джерел розтягують рядок на весь
   екран. Новий вузький клас, а не правка глобального .disclosure вище —
   решта розгорток на сторінках (форми реєстрації тощо) не мають скролитись
   всередині коробки з обрізаною висотою. */
.disclosure--scroll{max-height:300px; overflow-y:auto}

/* .prose — тіло бріфа (brief.html), рендерене через md_lite (admin/app.py):
   справжні <h3>/<ul>/<p>/<strong>/<em>/<a>, не preformatted-текст, тож читана
   міра (74ch) і вертикальні відступи між блоками — тут, а не в конкретних
   тегах (ті самі h1..h4{margin:0} і ul{margin:0 0 var(--sp-3)} з розділу 2
   лишаються загальними — тут лише простір МІЖ блоками прози). */
.prose{font-size:var(--fs-lg); line-height:1.7; max-width:74ch}
.prose h3{margin-top:var(--sp-5)}
.prose h3:first-child{margin-top:0}
.prose p,.prose ul{margin:0 0 var(--sp-4)}
.prose > :last-child{margin-bottom:0}

.meta{display:flex; flex-wrap:wrap; gap:var(--sp-2); align-items:center;
  font-size:var(--fs-sm); color:var(--text-dim)}
.breadcrumbs{display:flex; gap:var(--sp-2); align-items:center;
  font-size:var(--fs-sm); color:var(--text-dim)}
.pager{display:flex; gap:var(--sp-2); align-items:center;
  font-size:var(--fs-sm); color:var(--text-dim); font-variant-numeric:tabular-nums}

/* ───────────────────  10. Сторінка логіну (4.0)  ─────────────────────── */

.auth{
  min-height:100dvh; display:grid; place-items:center; padding:var(--sp-5);
  background:
    radial-gradient(70% 55% at 50% 0%, rgb(16 185 129/.06), transparent 70%),
    radial-gradient(60% 45% at 85% 100%, rgb(6 182 212/.06), transparent 70%),
    var(--bg);
}
/* text-align:center — точково на марці/заголовку/підвалі, а НЕ на картці:
   інакше центрується й підпис поля, і текст в інпуті. */
.auth__card{
  width:100%; max-width:380px; padding:var(--sp-6) var(--sp-5);
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-lg); box-shadow:var(--sh-2);
}
.auth__logo{display:block; height:56px; width:auto; margin:0 auto var(--sp-4)}
.auth__title,.auth__name,.auth__sub,.auth__foot{text-align:center}
.auth__title,.auth__name{font-size:var(--fs-xl); font-weight:650; letter-spacing:.01em}
.auth__name{margin-bottom:var(--sp-5)}
.auth__sub{margin:var(--sp-1) 0 var(--sp-5); font-size:var(--fs-sm); color:var(--text-dim)}
.auth__foot{margin:var(--sp-5) 0 0; font-size:var(--fs-sm); color:var(--text-faint)}
.auth__form{display:grid; gap:var(--sp-3); text-align:left}
.auth .alert{text-align:left}
.auth .field{margin-bottom:var(--sp-4)}
.auth .input{width:100%; padding:10px var(--sp-3)}
.auth .btn{padding:10px var(--sp-4)}

/* ──────────  11. Сумісність зі старими шаблонами (крок 2 → 3)  ───────── */
/* Ці класи вживаються в 9 ще не переписаних шаблонах. Правило специфікації:
   імена зберігаються 1:1, щоб сторінки отримали новий вигляд ДО переписування.
   Після кроку 3 частину з них можна прибрати (.msg, .grid-form, .cards). */

.muted{color:var(--text-dim)}
.wrap{overflow-x:auto; -webkit-overflow-scrolling:touch}
form.inline,.inline{display:inline}

.cards{display:flex; flex-wrap:wrap; gap:var(--sp-3); margin-bottom:var(--sp-2)}
.card{
  min-width:130px; padding:var(--sp-4) 18px;
  background:var(--surface); border:1px solid var(--line); border-radius:var(--r-lg);
}
.card .num{font-size:var(--fs-2xl); font-weight:700; line-height:1.1}
.card .lbl{font-size:var(--fs-sm); color:var(--text-dim)}   /* без uppercase, 3.5 */

.msg{padding:10px 14px; margin-bottom:var(--sp-4); border-radius:var(--r-md);
  border:1px solid transparent}
.msg.ok{color:var(--ok); background:var(--ok-bg); border-color:#17402F}
.msg.err{color:var(--bad); background:var(--bad-bg); border-color:#4A2229}

.grid-form{
  display:grid; grid-template-columns:140px 1fr; gap:var(--sp-2) var(--sp-3);
  max-width:720px; padding:var(--sp-4);
  background:var(--surface); border:1px solid var(--line); border-radius:var(--r-lg);
}
.grid-form textarea{font-family:var(--mono); min-height:90px}
@media (max-width:640px){
  .grid-form{grid-template-columns:1fr}
}

/* ── Перемикач мови (сайдбар) ───────────────────────────────────────
   EN за замовчуванням, UA за явним вибором. Форма з двох кнопок, а не
   <select>: два варіанти краще показати поруч, ніж ховати у випадайку. */
.langbar {
  display: flex;
  gap: 2px;
  padding: 2px;
  margin-bottom: 8px;
  background: var(--surface-2, #151c23);
  border: 1px solid var(--line, #232c36);
  border-radius: 8px;
}
.langbar__btn {
  flex: 1;
  padding: 4px 0;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--text-dim, #8a99a8);
  background: none;
  border: 0;
  border-radius: 6px;
  cursor: pointer;
}
.langbar__btn:hover { color: var(--text, #d9e1e8); }
.langbar__btn.is-active {
  color: var(--bg, #0B1014);
  background: linear-gradient(135deg, var(--brand-1, #10B981), var(--brand-2, #06B6D4));
}
.langbar__btn:focus-visible {
  outline: 2px solid var(--brand-1, #10B981);
  outline-offset: 1px;
}

/* ────────────────────────  12. AI-чат (4.9)  ──────────────────────────── */
/* Бульбашки: user праворуч на бренд-градієнті (та сама пара кольорів, що й
   .btn--primary), assistant ліворуч на нейтральній поверхні — розрізнення
   без жодного нового кольору поза токенами розділу 1. */

.chat__list{display:flex; flex-direction:column; gap:var(--sp-3)}
.chat__msg{display:flex; flex-direction:column; max-width:74ch}
.chat__msg--user{align-self:flex-end; align-items:flex-end}
.chat__msg--assistant,.chat__msg--error{align-self:flex-start; align-items:flex-start}

.chat__bubble{
  padding:var(--sp-3) var(--sp-4); border-radius:var(--r-lg);
  background:var(--surface-2); border:1px solid var(--line);
}
.chat__msg--user .chat__bubble{
  background:var(--brand-grad); color:var(--brand-ink); border-color:transparent;
}
.chat__text{margin:0; white-space:pre-wrap; word-break:break-word}
/* overflow-wrap:anywhere явно — навіть без пробілів (сирий URL із форуму)
   лінк не має розпирати бульбашку на вузькому мобільному екрані (мобільний
   прохід ≤480px, план 2026-08-31, дизайн п.2); word-break:break-word вище
   вже рятує звичайний текст, але для <a> дублюємо явно, а не покладаємось
   лише на успадкування. */
.chat__text a{color:inherit; text-decoration:underline; overflow-wrap:anywhere}

.chat__meta{
  display:flex; gap:var(--sp-2); align-items:center; margin-top:var(--sp-1);
  font-size:var(--fs-xs); color:var(--text-dim);
}
.chat__msg--user .chat__meta{flex-direction:row-reverse}

/* Розділ 2 редизайну: «Save as brief» тепер маленьке ⋯-меню (.menu) просто
   всередині .chat__meta, а не окрема видима кнопка/форма під бульбашкою —
   компактніше в межах рядка з часом/бейджами. */
.chat__msgmenu .menu__btn{min-width:auto; padding:0 6px; font-size:var(--fs-xs); border-color:transparent; background:none}
.chat__msgmenu .menu__btn:hover{background:var(--surface-2); border-color:var(--line)}

.chat__bubble--error{color:var(--bad); background:var(--bad-bg); border-color:#4A2229}

/* Індикатор «друкує» — три крапки, анімовані через @keyframes: reduced-motion
   уже глушить будь-яку анімацію глобально (розділ 3), тут нічого дублювати
   не треба. */
.chat__bubble--thinking{display:inline-flex; align-items:center; padding:10px var(--sp-4)}
.chat__dots{display:inline-flex; gap:4px}
.chat__dots span{
  width:6px; height:6px; border-radius:50%; background:var(--text-dim);
  animation:chat-dot 1.2s ease-in-out infinite;
}
.chat__dots span:nth-child(2){animation-delay:.15s}
.chat__dots span:nth-child(3){animation-delay:.3s}
.chat__thinking-text{margin-left:var(--sp-2); font-size:var(--fs-sm); color:var(--text-dim)}
@keyframes chat-dot{
  0%,80%,100%{opacity:.25; transform:translateY(0)}
  40%{opacity:1; transform:translateY(-3px)}
}

/* Композер (розділ 4 редизайну): власні surface/border/radius, а НЕ спільний
   .panel — той несе overflow:hidden (обрізає заокруглені кути під таблицями),
   а тут усередині спливає .chat__scope (.menu--up): overflow:hidden обрізав
   би його попап по межі композера. textarea на всю ширину зверху БЕЗ
   власної рамки (рамку вже дає сама панель — подвійна виглядала б неохайно),
   нижній рядок — [KB-scope] [Web search] [spacer] [Send]. Глобальне
   textarea{font-family:var(--mono)} (розділ 8) тут навмисно перевизначене:
   чат — жива мова, не код. */
.chat__composer{
  display:flex; flex-direction:column; gap:var(--sp-3); padding:var(--sp-3);
  background:var(--surface); border:1px solid var(--line); border-radius:var(--r-lg);
}
.chat__composer textarea{
  font-family:var(--font); border:0; background:none; padding:var(--sp-2) var(--sp-1);
  min-height:44px; max-height:16em; resize:vertical;
}
.chat__composer textarea:focus-visible{outline-offset:-2px}
.chat__composer textarea:disabled{opacity:.6}
.chat__composer-row{display:flex; align-items:center; gap:var(--sp-3); flex-wrap:wrap}
/* left:0, не спадкове right:0 (.menu__list розраховане на кнопки при ПРАВОМУ
   краї, як-от ⋯ у топбарі): кнопка scope стоїть при ЛІВОМУ краї композера, і
   right:0 витягав би список ліворуч ЗА межі екрана — знайдено наживо
   2026-08-11 на вузькому в'юпорті, чекбокси були обрізані до половини слова. */
.chat__scope .menu__list{max-height:60vh; overflow-y:auto; left:0; right:auto; min-width:260px}

/* ─────────────────────  13. Друк бріфа (4.8)  ─────────────────────────── */
/* «Зберегти як PDF» = window.print() (app.js, data-print) — чистий білий
   аркуш, а не темна тема кабінету: сайдбар/тулбар/кнопки/бейджі-керування
   ховаються, лишається заголовок екосистеми, дата і сама проза. */
@media print{
  .sidebar,.topbar,.controls,.scrim,.session-banner{display:none !important}
  .app{display:block}
  .content,.content--full{
    padding:0; margin:0; max-width:none; height:auto; overflow:visible;
  }
  body{background:#fff; color:#000}
  .panel{background:none; border:0; border-radius:0}
  .panel__foot{background:none; color:#000}
  .badge{display:none}
  .prose{color:#000; max-width:none}
  .prose a{color:#000; text-decoration:underline}
  a{color:#000}
}

/* ── 14. AI-чат: постійна панель історії справа (розділ 1 редизайну) ──
   Замінює колишню шухляду-по-URL (?hist=1): .chat-side тепер видима
   ЗАВЖДИ на десктопі, а не лише коли відкрита. Брейкпоінт 1100px —
   узгоджений із рештою дашборда (та сама межа, що й .with-rail вище). */
.chat-wrap{display:flex; height:100%; min-height:0}
.chat-col{
  flex:1 1 auto; min-width:0; display:flex; flex-direction:column; min-height:0;
  padding:var(--sp-4) var(--sp-5); gap:var(--sp-3);
}
.chat-col__head{flex:0 0 auto; display:flex; align-items:center; gap:var(--sp-3)}
/* Кнопка «History» — лише мобільний тригер оверлея нижче; на десктопі
   панель і так завжди видима, тож дублювати кнопку нема сенсу. */
/* margin-left:auto — кнопка при ПРАВОМУ краї (явне побажання Миколи:
   History «десь справа», з того самого боку, що й панель, яку вона відкриває). */
.chat-col__histbtn{display:none; margin-left:auto}
.chat__archived-banner{margin:0; flex:1 1 auto; display:flex; align-items:center; gap:var(--sp-3)}
.chat-col__scroll{flex:1; min-height:0; overflow-y:auto}
.chat-col__scroll > * + *{margin-top:var(--sp-4)}

.chat-side__scrim{display:none}

.chat-side{
  flex:0 0 300px; width:300px; min-height:0; overflow-y:auto;
  display:flex; flex-direction:column; gap:var(--sp-3);
  border-left:1px solid var(--line); padding:var(--sp-4);
}
.chat-side__newchat{flex:0 0 auto}
.chat-side__list{display:flex; flex-direction:column; gap:6px; min-height:0; overflow-y:auto}
.chat-side__item{
  position:relative; display:flex; align-items:flex-start; gap:4px;
  border-radius:var(--r-md);
}
.chat-side__item:hover{background:var(--surface-2)}
.chat-side__item.is-active{background:var(--surface-2); box-shadow:inset 2px 0 0 0 var(--brand-1)}
.chat-side__link{
  flex:1 1 auto; min-width:0; display:block; padding:8px 4px 8px 10px;
  color:var(--text); text-decoration:none;
}
.chat-side__link:hover{text-decoration:none}
.chat-side__preview{
  display:block; margin-bottom:4px; font-size:var(--fs-sm);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.chat-side__meta{display:flex; gap:6px; align-items:center; flex-wrap:wrap; font-size:var(--fs-xs); color:var(--text-dim)}
.chat-side__menu{flex:0 0 auto; margin:6px 6px 0 0}

@media (max-width:1099px){
  .chat-col__histbtn{display:inline-flex}
  .chat-side{
    position:fixed; inset:0 0 0 auto; z-index:40; width:320px; max-width:88vw;
    height:100dvh; background:var(--bg); border-left:1px solid var(--line);
    box-shadow:var(--sh-2); transform:translateX(100%); transition:transform .18s;
  }
  #chat-side-toggle:checked ~ .chat-side{transform:none}
  #chat-side-toggle:checked ~ .chat-side__scrim{
    display:block; position:fixed; inset:0; z-index:30; background:rgb(0 0 0/.55);
  }
}

/* Мобільний прохід /chat ≤480px (план 2026-08-31, дизайн п.2). У живому
   прев'ю (375px і 320px) знайдено РЕАЛЬНЕ горизонтальне переповнення:
   .chat-col__head і .chat__archived-banner (банер read-only
   Telegram-перегляду — текст попередження + «Back to current chat» +
   select моделі + «Create Brief») ідуть в один незгортний ряд ЗАРАЗ (без
   flex-wrap, на відміну від .chat__composer-row, у якого wrap уже є) —
   на вузькому екрані ряд вилазить за .content--full{overflow:hidden} і
   кнопка «History» (єдиний спосіб відкрити панель історії на мобільному!)
   мовчки зникає за межею екрана. wrap повертає її на власний рядок. */
@media (max-width:480px){
  .chat-col__head{flex-wrap:wrap; row-gap:var(--sp-2)}
  .chat__archived-banner{flex-wrap:wrap; row-gap:var(--sp-2)}
}

/* ─────────────  15. Findings: рівні фільтри (задача 1 аудиту)  ───────── */
/* `.filters` — форма-обгортка навколо .form-grid (основні поля) і
   <details class="disclosure"> (другорядні): flex-колонка з gap замість
   .toolbar + .disclosure (adjacent-sibling margin вище не спрацював би —
   тут disclosure ВСЕРЕДИНІ тієї самої форми, а не сусід після неї). */
.filters{display:flex; flex-direction:column; gap:var(--sp-3)}
.filters__actions{display:flex; gap:var(--sp-2)}
/* Порожній підпис-«привид»: та сама висота (font-size+line-height), що й у
   .field__label сусідніх полів, тож Filter/Reset вирівнюються по нижньому
   краю решти контролів, а не по верху комірки. visibility:hidden — НЕ
   display:none/position:absolute (.visually-hidden) — той знімає елемент
   із потоку, і вирівнювання знову ламається. */
.field__label--ghost{visibility:hidden}
/* Довгі назви знахідок (задача 1, п. «таблиця не пливе») — CSS-обрізання +
   title= у розмітці для повного тексту на ховері/скрінрідері. */
.cell--truncate{
  display:inline-block; max-width:46ch; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; vertical-align:bottom;
}

/* ────────────  16. Findings: непрочитане як у месенджерах (задача 3)  ── */
/* Крапка-маркер перед заголовком — той самий розмір/прийом, що й
   .session__dot (розділ 5), лише колір --brand-2/--info: НЕ --brand-1
   (той належить .item-row--lead/.b-lead — «лід», інша категорія уваги,
   яка може співіснувати на тому самому рядку). */
.unread-dot{
  display:inline-block; width:7px; height:7px; margin-right:6px;
  border-radius:50%; background:var(--brand-2); vertical-align:middle;
}
/* Крапка живе ВСЕРЕДИНІ .cell--truncate-якоря (items.html пояснює чому) —
   сиблінгом вона лишалася сама на рядку, коли вузька колонка переносила
   nowrap-якір цілим. */
.item-row--unread{background:color-mix(in srgb, var(--brand-2) 5%, transparent)}
.item-row--unread:hover{background:color-mix(in srgb, var(--brand-2) 11%, transparent)}
/* Лід + непрочитане одночасно — окремий, трохи насиченіший відтінок
   (вкладений color-mix: спершу 4% --brand-2 понад прозорий, тоді 4%
   --brand-1 понад той результат), щоб рядок лишався відрізним від «просто
   лід» чи «просто непрочитане» без другого box-shadow поверх першого. */
.item-row--lead.item-row--unread{
  background:color-mix(in srgb, var(--brand-1) 4%, color-mix(in srgb, var(--brand-2) 4%, transparent));
}
.item-row--lead.item-row--unread:hover{
  background:color-mix(in srgb, var(--brand-1) 8%, color-mix(in srgb, var(--brand-2) 8%, transparent));
}

/* ──────────  17. Компактний select моделі бріфа (задача 4 аудиту)  ───── */
/* Рядок items.html/composer chat.html не має розпухати від звичайного
   <select> (padding 7px 10px, розділ 8) — .select--sm тримає його на
   висоті .btn--sm поруч. */
select.select--sm{padding:2px 6px; font-size:var(--fs-sm); min-width:0}
/* У щільній таблиці /items закритий select розтягується під НАЙДОВШУ
   опцію («Sonnet · faster») і саме він давав останні ~80px горизонтального
   скролу (заміряно наживо 1071 проти 994). Обрізаний текст у закритому
   стані — чесна ціна за таблицю без скролу; випадний список показує повні
   назви як завжди. */
.table--dense select.select--sm{max-width:76px; text-overflow:ellipsis}
/* Другий і останній внесок у «без h-скролу»: 46ch заголовка лишали 37px
   переливу на 1280px — 40ch прибирають його з запасом, а повна назва
   однаково живе в title= (задача 1, заміряно наживо scrollWidth 1031→994). */
.table--dense .cell--truncate{max-width:40ch}

/* ───────────  18. Overview: needs attention і воронка (задача 6)  ────── */
/* «Unread findings» — та сама пара --brand-2/--info, що й .unread-dot/NAV-
   бейдж вище (одна візуальна категорія «непрочитане» по всьому дашборду),
   на відміну від .stat--lead (--brand-1, «лід» — інша категорія). */
.stat--unread{border-color:var(--info)}
.stat--unread .stat__num{color:var(--info)}

.issues{list-style:none; margin:0; padding:0}
.issue{
  display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between;
  gap:var(--sp-3); padding:var(--sp-3) var(--sp-4);
  border-bottom:1px solid var(--line-soft);
}
.issue:last-child{border-bottom:0}
.issue__text{font-size:var(--fs-md)}

/* Міні-воронка «This week» — цифрами в один рядок, кожен крок клікабельний
   (лінк на відповідний фільтр Findings), стрілка — суто декоративна. */
.funnel{display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-2)}
.funnel__step{
  display:flex; flex-direction:column; align-items:center; gap:2px;
  padding:var(--sp-2) var(--sp-4); border-radius:var(--r-md);
  color:inherit; text-decoration:none; text-align:center;
}
.funnel__step:hover{background:var(--surface-2); text-decoration:none}
.funnel__num{font-size:var(--fs-2xl); font-weight:700; line-height:1.1; font-variant-numeric:tabular-nums}
.funnel__lbl{margin-top:2px; font-size:var(--fs-sm); color:var(--text-dim)}
.funnel__arrow{color:var(--text-faint); font-size:var(--fs-lg)}

/* ──────────  19. Findings: дієта колонок (задача 1 аудиту 2026-08-12)  ─── */
/* Об'єднана колонка «Verdict» (Category+Confidence, items.html): дрібне
   muted-число впевненості під бейджем категорії — той самий візуальний
   принцип, що й .stat__lbl під .stat__num (розділ 9), лише в межах клітинки
   таблиці, тому власний, вужчий розмір. */
.verdict__conf{margin-top:2px; font-size:var(--fs-xs); color:var(--text-dim)}
/* Джерело обрізається помітно вужче за заголовок (46ch у .cell--truncate
   вище) — та сама вертикальна межа max-width, підмінена нижчим числом.
   Обидва класи стоять на одному елементі разом (items.html): порядок правил
   тут і вирішує, яке значення max-width переможе (каскад за джерелом, не
   специфічністю — обидва селектори рівні). */
/* 11ch, не 14ch: останні 18px h-скролу на 1280px сиділи саме тут
   (колонка Source 140px при сумі 1012 проти 994 доступних). */
.cell--truncate-sm{max-width:11ch}
/* Колонка дій /items: ОДИН рядок без переносів (прохання Миколи
   2026-08-12) — місце для цього звільнили вужчі падінги таблиці вище. */
.cell--actions{white-space:nowrap}
.cell--actions form.inline{white-space:nowrap}

/* ────────────  20. Overview: CSS-бар-чарти (задача 3 аудиту 2026-08-12)  ── */
/* Activity/Top ecosystems (dashboard.html) — CSP-safe ширина: НІЯКОГО
   style=, лише клас .w-N (крок 5%), підставлений із Python-бакетування
   (app.py: _bar_pct). .bar-cell — сам бар + число поруч, в одній клітинці
   таблиці. */
.bar-cell{display:flex; align-items:center; gap:var(--sp-2)}
.bar{height:8px; background:var(--surface-2); border-radius:4px; min-width:120px}
.bar__fill{height:100%; border-radius:4px; background:var(--neutral)}
.bar__fill--lead{background:var(--brand-1)}

.w-0{width:0%}
.w-5{width:5%}
.w-10{width:10%}
.w-15{width:15%}
.w-20{width:20%}
.w-25{width:25%}
.w-30{width:30%}
.w-35{width:35%}
.w-40{width:40%}
.w-45{width:45%}
.w-50{width:50%}
.w-55{width:55%}
.w-60{width:60%}
.w-65{width:65%}
.w-70{width:70%}
.w-75{width:75%}
.w-80{width:80%}
.w-85{width:85%}
.w-90{width:90%}
.w-95{width:95%}
.w-100{width:100%}

/* ──────────  21. Кастомне підтвердження — <dialog> (задача 4 аудиту)  ──── */
/* Заміна window.confirm() (app.js, розділ 4): один діалог на сторінку,
   стилізований під решту панелей (surface/border/radius/sh-2), а не
   браузерний дефолт (білий блок, чорний текст, системний шрифт). */
dialog.confirm{
  padding:0; border:1px solid var(--line); border-radius:var(--r-lg);
  background:var(--surface); color:var(--text); box-shadow:var(--sh-2);
  max-width:420px; width:calc(100vw - 2 * var(--sp-5));
}
dialog.confirm::backdrop{background:rgb(0 0 0/.55)}
.confirm__body{padding:var(--sp-5) var(--sp-4) var(--sp-4)}
.confirm__text{margin:0; font-size:var(--fs-md); white-space:pre-wrap}
.confirm__actions{
  display:flex; justify-content:flex-end; gap:var(--sp-2);
  padding:var(--sp-3) var(--sp-4); border-top:1px solid var(--line-soft);
  background:var(--surface-2); border-radius:0 0 var(--r-lg) var(--r-lg);
}

/* ──────  22. Бріф як документ, не як рядок адмінки (фіча 2026-08-31)  ──── */
/* brief.html: тижневі AI-звіти («Weekly grants & RFPs — …», «Weekly
   discovery — …») тепер саме тут читає СЕО — за посиланням із Telegram,
   часто з телефону. Ціль розділу: типографіка читання (колонка ~72ch,
   17px/1.65, ієрархія заголовків), а не адмін-щільність решти дашборда.

   .brief-head__title — заголовок бріфа ВСЕРЕДИНІ .panel__head (розмітка й
   базові flex/gap/border-bottom — розділ 9, БЕЗ ЗМІН тут). flex:1 1 100% —
   стандартний трюк «примусовий перенос рядка всередині flex-wrap»: заголовок
   займає весь рядок сам, бейджі екосистеми/tier/model/tokens + дата, що
   йдуть за ним у розмітці, автоматично переносяться на другий рядок —
   «мета-стрічка під заголовком» без жодного додаткового <div>-обгортки. */
.brief-head__title{
  flex:1 1 100%; margin:0 0 var(--sp-1);
  font-size:var(--fs-2xl); font-weight:700; line-height:var(--lh-tight);
}

/* .brief-doc — ДРУГИЙ клас на тому самому елементі, що й .prose (розділ 12:
   `class="prose brief-doc"` у brief.html). .prose лишається незайманим — його
   й далі рендерить keywords.html (advice_md), тому базові розміри там мають
   не зрушити. .brief-doc лише додає/перевизначає те, що властиво САМЕ
   довгому документу: ширину колонки, розмір і lh «під читання» (17/1.65 —
   трохи більші за .prose 16/1.7, читання довгого тексту, а не короткої
   поради), заголовки з відступом зверху, перенос довгих URL і таблиці. */
.brief-doc{
  max-width:72ch; margin:0 auto; font-size:17px; line-height:1.65;
}
.brief-doc h3{margin:var(--sp-6) 0 var(--sp-2); font-size:var(--fs-xl); font-weight:700}
.brief-doc h3:first-child{margin-top:0}
.brief-doc p,.brief-doc ul{margin:0 0 var(--sp-4)}
.brief-doc li+li{margin-top:var(--sp-1)}
/* Sources-розділи тижневих звітів рясніють довгими forum-URL — без цього
   правила один такий рядок ламає .brief-doc на 72ch у горизонтальний скрол
   усієї сторінки на телефоні (anywhere, не break-word: розриває і посеред
   довгого сегмента без дефісів/слешів, а не лише на «природних» межах). */
.brief-doc a{overflow-wrap:anywhere}
/* `md_lite` (admin/app.py) сьогодні НЕ вміє таблиці — сирий `<table>` у
   тексті LLM після escape-first проходу назавжди лишається текстом, тегом
   стати не може (розділ 4.8/4.9, той самий принцип, що й hl()/linkify()).
   Правило нижче — свідомий заділ «на випадок»: якщо рендерер колись
   навчиться таблицям (deadline-таблиці в бріфах — цілком очікувана вимога),
   він вставить ГОЛИЙ `<table>` прямо в потік .brief-doc (без обгортки —
   .tablewrap розділу 7 сюди не дотягнеться, бо html_parts у md_lite плоский
   список рядків, не дерево). `display:block; overflow-x:auto` на самій
   `<table>` — CSS-заміна .tablewrap там, де обгортки в розмітці немає. */
.brief-doc table{
  display:block; overflow-x:auto; -webkit-overflow-scrolling:touch;
  max-width:100%; border-collapse:collapse; font-size:var(--fs-sm);
  border:1px solid var(--line); border-radius:var(--r-md);
}
.brief-doc th,.brief-doc td{
  padding:6px 10px; text-align:left; vertical-align:top;
  border-bottom:1px solid var(--line-soft);
}
.brief-doc th{color:var(--text-dim); font-weight:600; white-space:nowrap}
.brief-doc tbody tr:last-child td{border-bottom:0}

/* Друк («Save as PDF», app.js data-print): розділ 13 вище вже ховає
   сайдбар/topbar/controls/badges і скидає .content/.prose до повної ширини
   й чорного тексту на білому — .brief-head__title/.brief-doc успадковують
   колір від body{color:#000} звідти без жодних додаткових правил. Єдине,
   що варто явно доскинути ТУТ — max-width:72ch у звичайному режимі не
   повинен пережити роздрук вузькою колонкою посеред аркуша A4 (той самий
   намір, що й .prose{max-width:none} у розділі 13, лише для нового класу). */
@media print{
  .brief-doc{max-width:none}
}

/* Мобільний прохід специфічно під /briefs/{id} (задача з фічі 2026-08-31):
   .brief-panel — той самий <article class="panel …">, лише з додатковим
   класом для сторінкового скоупу — свідомо НЕ чіпаємо .content/.panel__body
   напряму (розділи 2/9): ті самі класи стоять на кожній іншій сторінці
   дашборда, зменшення падінгів там — поза межами цієї фічі. 480px, не 640
   (розділ 6 вище вже покриває планшет/розкладку сайдбара) — це вужчий,
   телефонний брейкпоінт. Текст тіла — 16px, не менше (вимога: readable body
   лишається ≥16px на будь-якій ширині). */
@media (max-width:480px){
  .brief-panel .panel__head{padding:var(--sp-3)}
  .brief-panel .panel__body{padding:var(--sp-3)}
  .brief-head__title{font-size:var(--fs-xl)}
  .brief-doc{font-size:16px; line-height:1.6}
}

/* ─────────────  23. Share-перегляд бріфа (magic-лінк, /share/)  ───────────
   Той самий .brief-doc (розділ 22) несе типографіку; тут лише каркас
   сторінки БЕЗ сайдбара: вузька колонка документа по центру, шапка з
   маркою і футер-запрошення увійти. Жодних дій — read-only за задумом. */

.share-page{background:var(--bg)}
.share{max-width:760px; margin:0 auto; padding:var(--sp-5) var(--sp-4) var(--sp-6)}
.share__brand{padding:0; margin-bottom:var(--sp-5); display:inline-flex}
.share__head{margin-bottom:var(--sp-5)}
.share__title{font-size:var(--fs-2xl); line-height:var(--lh-tight); margin:0 0 var(--sp-2)}
.share__meta{display:flex; flex-wrap:wrap; gap:var(--sp-2); align-items:center;
  color:var(--text-dim); font-size:var(--fs-sm)}
.share__foot{margin-top:var(--sp-6); padding-top:var(--sp-4);
  border-top:1px solid var(--line)}
@media (max-width:480px){
  .share{padding:var(--sp-4) var(--sp-3) var(--sp-5)}
  .share__title{font-size:var(--fs-xl)}
}
