/* ============================================================================
   Design tokens.

   Кожен токен визначено ОДИН раз через `light-dark()`. Тему перемикає
   `color-scheme`, а не другий набір змінних:

       :root                      → color-scheme: light dark  (як в ОС)
       :root[data-theme="light"]  → color-scheme: light
       :root[data-theme="dark"]   → color-scheme: dark

   Тому світла тема — це `document.documentElement.dataset.theme = 'light'`
   і більше нічого. Заразом на неї перемикаються й нативні контроли
   (календар у <input type="date">, список у <select>, смуги прокрутки),
   чого набором CSS-змінних не досягти.
   ========================================================================= */

:root {
	color-scheme: light dark;

	/* Поверхні: bg — тло сторінки, surface — картка, 2 — вкладене, 3 — наведення */
	--bg:        light-dark(#f4f6f9, #0e1116);
	--surface:   light-dark(#ffffff, #161a21);
	--surface-2: light-dark(#f1f4f8, #1c212a);
	--surface-3: light-dark(#e7ecf3, #232935);
	--border:    light-dark(#dde3ec, #29303c);
	--border-strong: light-dark(#c4cddb, #3a4351);

	--text:      light-dark(#111827, #e8ecf2);
	--text-dim:  light-dark(#5b6675, #939eae);
	--text-mute: light-dark(#8a94a3, #6d7787);

	--accent:       light-dark(#2563eb, #6ea2ff);
	--accent-hover: light-dark(#1d4ed8, #8ab4ff);
	--accent-fg:    light-dark(#ffffff, #0b1220);
	/* Заливка під акцентом: підсвітка рядка, активний пункт меню, .bar */
	--accent-soft:  color-mix(in srgb, var(--accent) 12%, transparent);

	--danger: light-dark(#c0342b, #ff8a80);
	--ok:     light-dark(#127a41, #6ee7a8);
	--warn:   light-dark(#8a5b00, #f0c15c);

	/* Тіні й підкладка діалогу — теж токени: на світлому потрібна інша
	   прозорість, інакше картки виглядають брудними. */
	/* light-dark() приймає ЛИШЕ колір. `hsl(var(--shadow-color) / var(--shadow-a))`,
	   де обидва токени — light-dark() з числами, це invalid at computed-value time:
	   Chrome мовчки викидав УСІ box-shadow у застосунку (картки теж). Тому тінь
	   тепер готовий колір, а не компоненти. */
	--shadow-1: light-dark(hsl(215 25% 27% / .06), hsl(220 40% 2% / .40));
	--shadow-2: light-dark(hsl(215 25% 27% / .09), hsl(220 40% 2% / .50));
	--shadow-3: light-dark(hsl(215 25% 27% / .13), hsl(220 40% 2% / .70));
	--shadow-sm: 0 1px 2px var(--shadow-1);
	--shadow-md: 0 2px 4px var(--shadow-1),
	             0 6px 16px -6px var(--shadow-2);
	--shadow-lg: 0 18px 50px -12px var(--shadow-3);
	--backdrop:  light-dark(hsl(215 25% 27% / .35), hsl(220 40% 2% / .6));

	/* Об'єм кнопки: світло згори. Блик — background-IMAGE поверх будь-якого
	   background-color, тож :hover міняє лише колір і градієнт лишається. */
	--btn-sheen: linear-gradient(rgb(255 255 255 / .07), rgb(0 0 0 / .03));
	/* 1px згори світліше, 1px знизу темніше — саме ця пара і читається як об'єм.
	   Рамки в кнопки немає: inset-тінь малюється ПІД border, і 1px рамка з'їдала
	   б рівно ці два пікселі. */
	--btn-raise: inset 0 1px 0 light-dark(rgb(255 255 255 / .55), rgb(255 255 255 / .22)),
	             inset 0 -1px 0 light-dark(rgb(0 0 0 / .10), rgb(0 0 0 / .22)),
	             0 1px 1px var(--shadow-1);
	--btn-press: inset 0 1px 2px -1px var(--shadow-3);

	/* Одна висота на всі контроли: input, select, date, button, .quiet.
	   Саме через неї ряд фільтрів вирівнюється по піксель. */
	--control-h: 36px;
	--radius-sm: 6px;
	--radius:    9px;
	--radius-lg: 14px;
	--gap: 16px;
	--sidebar-w: 236px;
	--topbar-h: 56px;

	--font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
	--ease: cubic-bezier(.2, .7, .3, 1);
}

:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"]  { color-scheme: dark; }

@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after { transition: none !important; animation: none !important; }
}

/* ---- base ---- */

* { box-sizing: border-box; }

/* Місце під смугу прокрутки резервується завжди. Без цього коротка вкладка
   («Історія» на два рядки) і довга («Робота») мають різну ширину контенту, і
   при переході вся сторінка — шапка, кнопки, таблиця — стрибала на 15px убік. */
html { scrollbar-gutter: stable; }

body {
	margin: 0;
	font-family: var(--font);
	font-size: 15px;
	line-height: 1.5;
	/* Цифри однакової ширини скрізь: суми в колонці мають вишиковуватись. */
	font-variant-numeric: tabular-nums;
	color: var(--text);
	background: var(--bg);
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
}

a { color: var(--accent); text-underline-offset: 2px; }
a:hover { color: var(--accent-hover); }

h1 { font-size: 23px; line-height: 1.25; letter-spacing: -.01em; margin: 0; text-wrap: balance; }
h2 { font-size: 16px; line-height: 1.35; margin: 0 0 12px; letter-spacing: -.005em; }
h3 { font-size: 14px; margin: 0 0 8px; }
/* У рядах дій заголовок стоїть поруч із кнопками — свій відступ він там не має. */
.card-head h2, .card-head h3, .page-head h2, .board-col h2 { margin-bottom: 0; }

.sub { color: var(--text-dim); font-size: 13px; margin: 0; }
.right { text-align: right; }
.archived { opacity: .55; }
.nowrap { white-space: nowrap; }
.danger { color: var(--danger); }
.notes { white-space: pre-line; margin: 0; }
.diff { color: var(--text-dim); font-size: 13px; }
.strong { font-weight: 600; text-decoration: none; color: var(--text); }
.strong:hover { color: var(--accent); }
.sub-line { display: block; font-size: 12px; color: var(--text-dim); }

.skip {
	position: absolute; left: -9999px;
	background: var(--surface); padding: 10px 14px; z-index: 100;
	border-radius: var(--radius-sm); box-shadow: var(--shadow-md);
}
.skip:focus { left: 8px; top: 8px; }

:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
	border-radius: var(--radius-sm);
}

.sr-only {
	position: absolute; width: 1px; height: 1px;
	overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* ============================================================================
   Shell
   ========================================================================= */

.shell { display: flex; min-height: 100vh; }

.sidebar {
	width: var(--sidebar-w);
	flex: 0 0 var(--sidebar-w);
	background: var(--surface);
	border-right: 1px solid var(--border);
	display: flex;
	flex-direction: column;
	position: sticky;
	top: 0;
	height: 100vh;
	z-index: 30;
}

.brand {
	display: flex;
	/* Базова лінія назви = низ логотипа: у replaced-елемента базова лінія і є
	   нижній край. wrap + align-content лишають блок по центру топбару —
	   самий baseline притиснув би його до верху рядка. */
	align-items: baseline;
	flex-wrap: wrap;
	align-content: center;
	gap: 10px;
	font-family: Georgia, "Times New Roman", serif;
	font-size: 24px;
	/* Золото з логотипа. На світлому тлі сам #ffd700 дає контраст ~1.3:1 —
	   назва фірми перестала б читатись, тому там темніший відтінок того ж тону.
	   24px звичайної ваги — це вже «великий текст» за WCAG, тож поріг 3:1. */
	color: light-dark(#a67c00, #ffd700);
	/* Вага звичайна: h1 на екрані входу інакше був би жирним, а .brand у шапці — ні. */
	font-weight: 400;
	letter-spacing: -.01em;
	height: var(--topbar-h);
	flex: none;
	/* 20px = padding у .sidebar ul (10) + у .sidebar a (10): лого стає в одну
	   колонку з іконками меню. */
	padding: 0 20px;
	border-bottom: 1px solid var(--border);
}

.sidebar ul {
	list-style: none;
	margin: 0;
	padding: 10px 10px 4px;
	flex: 1;
	overflow-y: auto;
	display: flex;
	flex-direction: column;
	gap: 2px;
}

.sidebar a {
	position: relative;
	display: flex;
	align-items: center;
	gap: 11px;
	padding: 8px 10px;
	border-radius: var(--radius-sm);
	color: var(--text-dim);
	text-decoration: none;
	font-size: 14px;
	line-height: 20px;
	transition: background .12s var(--ease), color .12s var(--ease);
}

.sidebar a:hover { background: var(--surface-2); color: var(--text); }

.sidebar a[aria-current="page"] {
	background: var(--accent-soft);
	color: var(--accent);
	font-weight: 550;
}

/* Смужка ліворуч — щоб активний пункт читався і без кольору. */
.sidebar a[aria-current="page"]::before {
	content: "";
	position: absolute;
	left: -10px; top: 50%;
	width: 3px; height: 20px;
	transform: translateY(-50%);
	border-radius: 0 3px 3px 0;
	background: var(--accent);
}

.sidebar svg {
	width: 18px; height: 18px; flex: none;
	fill: none; stroke: currentColor; stroke-width: 1.7;
	stroke-linecap: round; stroke-linejoin: round;
}

.sidebar-foot {
	border-top: 1px solid var(--border);
	padding: 10px;
	display: flex;
	flex-direction: column;
	align-items: stretch;
	gap: 2px;
	font-size: 13px;
	flex: none;
}

/* У підвалі меню «Налаштування» та «Вийти» — пункти списку, а не кнопки. */
.sidebar-foot .quiet,
.sidebar-foot button.link {
	justify-content: flex-start;
	gap: 11px;          /* як у .sidebar a — іконки стоять в одну колонку */
	height: 32px;
	padding: 0 10px;
	border: none;
	background: none;
	box-shadow: none;
	border-radius: var(--radius-sm);
	font-size: 13px;
	color: var(--text-dim);
	width: 100%;
}
.sidebar-foot .quiet:hover,
.sidebar-foot button.link:hover { background: var(--surface-2); color: var(--text); }
.sidebar-foot .quiet:active,
.sidebar-foot button.link:active { box-shadow: none; }
.sidebar-foot form { margin: 0; }

.whoami {
	color: var(--text-mute);
	padding: 4px 10px 6px;
	font-size: 12px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.content { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
	height: var(--topbar-h);
	flex: none;
	border-bottom: 1px solid var(--border);
	background: color-mix(in srgb, var(--surface) 82%, transparent);
	backdrop-filter: saturate(1.6) blur(10px);
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 0 var(--gap);
	position: sticky;
	top: 0;
	z-index: 20;
}

/* Кнопка-гамбургер: чекбокс усередині <label>, стан ловить :has() у .shell.
   ponytail: нуль JS — меню має відкриватися й тоді, коли скрипт не завантажився. */
.nav-toggle {
	display: none;
	align-items: center;
	justify-content: center;
	width: var(--control-h); height: var(--control-h);
	flex: none;
	margin-left: -6px;
	border-radius: var(--radius-sm);
	color: var(--text-dim);
	cursor: pointer;
}
.nav-toggle:hover { background: var(--surface-2); color: var(--text); }
.nav-toggle:has(:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.nav-toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.nav-toggle svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.nav-scrim { display: none; }

/* Перемикач теми. Стан живе на <html data-theme>, тож яку іконку показати —
   вирішує CSS, а не JS: три <svg> у кнопці, видима завжди одна. */
.icon-btn {
	width: var(--control-h); height: var(--control-h);
	padding: 0; flex: none;
	background: none; color: var(--text-dim);
	box-shadow: none;
}
.icon-btn:hover { background: var(--surface-2); color: var(--text); }
.icon-btn:active { box-shadow: none; }
.icon-btn svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
/* Іконка = поточна тема. Поки data-theme немає, її знає лише ОС — звідси @media. */
[data-theme-toggle] .i-dark { display: none; }
@media (prefers-color-scheme: dark) {
	:root:not([data-theme]) [data-theme-toggle] .i-light { display: none; }
	:root:not([data-theme]) [data-theme-toggle] .i-dark { display: block; }
}
:root[data-theme="light"] [data-theme-toggle] .i-light,
:root[data-theme="dark"] [data-theme-toggle] .i-dark { display: block; }
:root[data-theme="light"] [data-theme-toggle] .i-dark,
:root[data-theme="dark"] [data-theme-toggle] .i-light { display: none; }

/* `flex`, а не `width: min(380px, 100%)`: у флекс-елемента `min-width` за
   замовчуванням `auto`, тож при 100% він відмовлявся стискатися й виштовхував
   таймер і перемикач теми за край екрана — на телефоні перемикач теми був
   недосяжний узагалі (scrollWidth 580 при clientWidth 485). */
.search-trigger {
	display: flex;
	align-items: center;
	gap: 8px;
	height: var(--control-h);
	flex: 1 1 auto;
	min-width: 0;
	max-width: 380px;
	padding: 0 10px;
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	background: var(--bg);
	box-shadow: none;
	color: var(--text-mute);
	cursor: pointer;
	font: inherit;
	font-size: 13px;
	transition: border-color .12s var(--ease), background .12s var(--ease);
}

.search-trigger:hover { border-color: var(--border-strong); background: var(--surface-2); }
.search-trigger span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.search-trigger svg {
	width: 15px; height: 15px; flex: none;
	fill: none; stroke: currentColor; stroke-width: 1.8;
}

.search-trigger kbd {
	margin-left: auto;
	flex: none;
	font: inherit; font-size: 11px;
	line-height: 16px;
	border: 1px solid var(--border);
	border-radius: 4px;
	padding: 0 5px;
	color: var(--text-mute);
}

/* Таймер у верхній панелі */
.timer { margin-left: auto; display: flex; align-items: center; gap: 10px; font-size: 13px; }
.timer-run { display: flex; align-items: center; gap: 8px; }
.timer-run[hidden] { display: none; }
.timer-clock {
	font-size: 15px; font-weight: 650;
	letter-spacing: .01em;
	color: var(--accent);
}
.timer button { height: 30px; padding: 0 12px; font-size: 13px; }
.timer button.link { padding: 0 6px; }
.timer [data-timer-msg]:empty { display: none; }

/* Хто ще на цьому записі. Порожній — не займає місця й не малює роздільник. */
.live-editors { font-size: 13px; color: var(--text-dim); white-space: nowrap; }
.live-editors:empty { display: none; }

/* `clip`, не `hidden`: обрізає, але не робить main новим скрол-контейнером,
   тож sticky-шапка й sticky-колонка таблиці працюють як працювали. Сторінка
   вбік не їде ніколи — вбік їдуть .table-wrap і .cal, кожен усередині себе. */
main { padding: var(--gap); flex: 1; min-width: 0; overflow-x: clip; }
.page { max-width: 1120px; display: flex; flex-direction: column; gap: var(--gap); }
.page.wide   { max-width: 1440px; }
.page.narrow { max-width: 820px; }

/* ============================================================================
   Контроли: одна висота, один радіус, один фокус
   ========================================================================= */

label { display: block; font-size: 13px; font-weight: 500; color: var(--text-dim); }

input, select, textarea {
	font: inherit;
	font-size: 14px;
	color: var(--text);
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	width: 100%;
	max-width: 100%;
	height: var(--control-h);
	padding: 0 10px;
	transition: border-color .12s var(--ease), box-shadow .12s var(--ease);
}

/* Chrome малює нативний календар/лічильник — зайвий внутрішній відступ прибираємо,
   щоб дата стояла в тій самій сітці, що й текстове поле. */
input[type="date"], input[type="time"], input[type="datetime-local"], input[type="number"] {
	padding-right: 8px;
}
input::-webkit-calendar-picker-indicator { opacity: .55; cursor: pointer; }
input::-webkit-calendar-picker-indicator:hover { opacity: 1; }

select { padding-right: 6px; }

textarea {
	height: auto;
	min-height: calc(var(--control-h) * 2.2);
	padding: 8px 10px;
	line-height: 1.45;
	resize: vertical;
}

input[type="file"] { padding: 6px 10px; height: auto; line-height: 22px; }
input::placeholder, textarea::placeholder { color: var(--text-mute); }

input:hover:not(:disabled), select:hover:not(:disabled), textarea:hover:not(:disabled) {
	border-color: var(--border-strong);
}

input:focus, select:focus, textarea:focus {
	outline: none;
	border-color: var(--accent);
	box-shadow: 0 0 0 3px var(--accent-soft);
}

input:disabled, select:disabled, textarea:disabled {
	background: var(--surface-2);
	color: var(--text-mute);
	cursor: not-allowed;
}

input[type="checkbox"], input[type="radio"] {
	width: 16px; height: 16px;
	accent-color: var(--accent);
	flex: none;
	padding: 0;
	cursor: pointer;
}

label > input, label > select, label > textarea { margin-top: 5px; color: var(--text); }

/* ---- підпис під полем ----
   Рамку червонить сусідній span через `:has(+ …)`, тому в жодне з полів не
   треба дописувати aria-invalid чи клас: одне правило замість атрибута на
   кожному <input>. Умова одна — valid::err() стоїть одразу після контролю.
   Помилка блокує збереження, попередження — ні (див. lib/valid.php). */
.field-err, .field-warn {
	display: block;
	margin-top: 4px;
	font-size: 12px;
	font-weight: 400;
	line-height: 1.35;
}
.field-err  { color: var(--danger); }
.field-warn { color: var(--warn); }

:is(input, select, textarea):has(+ .field-err)  { border-color: var(--danger); }
:is(input, select, textarea):has(+ .field-warn) { border-color: var(--warn); }
:is(input, select, textarea):has(+ .field-err):focus {
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 18%, transparent);
}
:is(input, select, textarea):has(+ .field-warn):focus {
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--warn) 18%, transparent);
}

/* У рядковій формі підпис — окремий рядок під нею, інакше він став би ще однією
   колонкою й розсунув поля. */
.row-form > :is(.field-err, .field-warn) { flex: 1 0 100%; margin-top: 0; }

/* ---- повторювані контактні дані ---- */
.details { display: flex; flex-direction: column; gap: 8px; }
.details > button { align-self: start; }

.detail-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.detail-row > input:first-child { flex: 0 1 170px; min-width: 0; }
.detail-row > input + input     { flex: 1 1 240px; min-width: 0; }

/* `order` лишає підпис НАСТУПНИМ братом свого input — без цього не спрацював би
   `input:has(+ .field-err)` вище, — але малює його останнім, окремим рядком. */
.detail-row > :is(.field-err, .field-warn) { order: 1; flex: 1 0 100%; margin-top: 0; }

.detail-drop {
	flex: none;
	width: var(--control-h); height: var(--control-h);
	padding: 0;
	font-size: 18px; line-height: 1;
	color: var(--text-mute);
}
.detail-drop:hover { color: var(--danger); }

/* ---- поле файлу (views/shared/upload.php + public/js/upload.js) ----
   Сам <input type="file"> лишається в DOM і лишається тим, що надсилається;
   ховаємо лише його рідний вигляд, бо стилізувати «Choose File» не можна. */
.drop-field { display: block; min-width: 0; }
.drop-cap { display: block; font-size: 13px; font-weight: 500; color: var(--text-dim); }

.drop {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 8px;
	margin-top: 5px;
	padding: 18px 14px;
	text-align: center;
	background: var(--surface);
	border: 1px dashed var(--border-strong);
	border-radius: var(--radius);
	cursor: pointer;
	transition: border-color .12s var(--ease), background .12s var(--ease);
}
.drop:hover { border-color: var(--accent); }
.drop input[type="file"] {
	/* Не display:none — так поле лишається фокусованим із клавіатури, а без
	   фокуса не працювала б вставка з буфера. */
	position: absolute;
	width: 1px; height: 1px;
	opacity: 0;
	pointer-events: none;
}
.drop input:focus-visible + .drop-hint { text-decoration: underline; }
.drop-hint { font-size: 13px; color: var(--text-dim); line-height: 1.45; }
.drop-hint b { color: var(--accent); font-weight: 500; }

.drop-field.over .drop { border-color: var(--accent); background: var(--accent-soft); }
.drop-field.has-files .drop-hint { display: none; }
.drop-field:not(.has-files) .drop-clear { display: none; }
.drop-field:has(.field-err) .drop { border-color: var(--danger); }

.drop-list { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
.drop-list .chip {
	padding: 4px 9px;
	font-size: 13px;
	color: var(--text);
	background: var(--surface-2);
	border: 1px solid var(--border);
	border-radius: 999px;
}

.drop-clear { margin-top: 6px; }

/* ---- <select> із пошуком (public/js/select.js) ----
   Кнопка стоїть на місці схованого <select>, тому має виглядати як він, а не
   як кнопка: та сама поверхня, той самий фокус, та сама стрілка. */
label:has(> .combo) { position: relative; }

.combo {
	display: flex;
	justify-content: space-between;
	width: 100%;
	margin-top: 5px;
	padding: 0 6px 0 10px;
	font-weight: 400;
	text-align: left;
	color: var(--text);
	background: var(--surface);
	border: 1px solid var(--border);
	box-shadow: none;
}
.combo::after {
	content: '';
	flex: none;
	width: 8px; height: 8px;
	margin-left: 8px;
	border: solid var(--text-dim);
	border-width: 0 1.5px 1.5px 0;
	transform: translateY(-2px) rotate(45deg);
}
.combo:hover { background: var(--surface); border-color: var(--border-strong); }
.combo[aria-expanded="true"], .combo:focus-visible {
	border-color: var(--accent);
	box-shadow: 0 0 0 3px var(--accent-soft);
	outline: none;
}
.combo:has(+ .field-err)  { border-color: var(--danger); }
.combo:has(+ .field-warn) { border-color: var(--warn); }

.combo-pop {
	position: absolute;
	z-index: 30;
	top: 100%; left: 0;
	/* Список не мусить бути завширшки з поле: назва справи туди не влазить, а
	   обрізаний список нема сенсу шукати. */
	min-width: 100%;
	width: max-content;
	max-width: min(460px, 80vw);
	margin-top: 4px;
	padding: 6px;
	background: var(--surface);
	border: 1px solid var(--border-strong);
	border-radius: var(--radius);
	box-shadow: var(--shadow-lg);
}
.combo-pop ul { max-height: 260px; overflow-y: auto; margin: 6px 0 0; padding: 0; list-style: none; }
.combo-pop li {
	padding: 7px 9px;
	border-radius: var(--radius-sm);
	font-size: 14px;
	cursor: pointer;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.combo-pop li[aria-selected="true"] { background: var(--accent); color: var(--accent-fg); }
.combo-pop li:hover { background: var(--surface-2); }
.combo-pop li[aria-selected="true"]:hover { background: var(--accent); }

/* ---- сегментований перемикач замість <select> на 2–3 сталі варіанти ----
   Обгортка — fieldset (усередині радіокнопки з власними мітками), але виглядати
   має як звичайне поле, а не як рамкована група: тому скидаємо і рамку, і
   `grid-column: 1 / -1`, який fieldset отримує за замовчуванням. */
fieldset.seg-field {
	grid-column: auto;
	border: 0;
	padding: 0;
	margin: 0;
	min-width: 0;
}
fieldset.seg-field.wide { grid-column: 1 / -1; }
fieldset.seg-field > legend {
	padding: 0;
	font-size: 13px;
	font-weight: 500;
	letter-spacing: normal;
	text-transform: none;
	color: var(--text-dim);
}

.seg {
	display: flex;
	flex-wrap: wrap;
	gap: 4px;
	margin-top: 5px;
	padding: 3px;
	background: var(--surface-2);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
}
.seg label {
	flex: 1 1 auto;
	display: flex; align-items: center; justify-content: center;
	min-height: calc(var(--control-h) - 8px);
	padding: 0 10px;
	font-size: 14px; font-weight: 400;
	color: var(--text-dim);
	border-radius: calc(var(--radius-sm) - 2px);
	white-space: nowrap;
	cursor: pointer;
	transition: background .12s var(--ease), color .12s var(--ease);
}
.seg input { position: absolute; opacity: 0; pointer-events: none; }
.seg label:hover { color: var(--text); }
.seg label:has(input:checked) { background: var(--surface); color: var(--text); box-shadow: var(--shadow-sm); }
.seg label:has(input:focus-visible) { box-shadow: 0 0 0 2px var(--accent); }

/* ---- buttons ---- */

button, .btn, a.btn, .quiet, a.quiet {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 7px;
	height: var(--control-h);
	padding: 0 14px;
	flex: none;
	font: inherit;
	font-size: 14px;
	font-weight: 500;
	line-height: 1;
	white-space: nowrap;
	border-radius: var(--radius-sm);
	border: 0;
	background-color: var(--accent);
	background-image: var(--btn-sheen);
	box-shadow: var(--btn-raise);
	color: var(--accent-fg);
	text-decoration: none;
	cursor: pointer;
	transition: background-color .12s var(--ease), color .12s var(--ease),
	            box-shadow .12s var(--ease);
}

button:hover, .btn:hover, a.btn:hover { background-color: var(--accent-hover); color: var(--accent-fg); }
button:active, .btn:active, a.btn:active { box-shadow: var(--btn-press); background-image: none; }
button:disabled { opacity: .55; cursor: not-allowed; box-shadow: var(--btn-raise); }
button:disabled:hover { background-color: var(--accent); }

/* Вторинна дія: «Скинути», «Експорт CSV», «Скасувати», навігація календаря.
   Раніше це були голі посилання — саме вони й ламали вирівнювання рядів.
   Рамки немає ні в кого — контур вторинної дає inset-кільце в тіні, останнє в
   списку, щоб світлий і темний 1px лишалися зверху. */
.quiet, a.quiet {
	background-color: var(--surface);
	box-shadow: var(--btn-raise), inset 0 0 0 1px var(--border);
	color: var(--text-dim);
	font-weight: 500;
}
.quiet:hover, a.quiet:hover {
	background-color: var(--surface-2);
	box-shadow: var(--btn-raise), inset 0 0 0 1px var(--border-strong);
	color: var(--text);
}
.quiet:active, a.quiet:active {
	box-shadow: var(--btn-press), inset 0 0 0 1px var(--border-strong);
	background-image: none;
}

/* Текстова кнопка (Видалити, Прибрати, Вийти) — без рамки, але тієї ж висоти,
   щоб у ряду дій стояти на одній лінії з рештою. */
button.link {
	background: none;
	box-shadow: none;
	color: var(--accent);
	border: none;
	padding: 0 8px;
	width: auto;
}
button.link:hover { background: var(--surface-2); color: var(--accent-hover); }
button.link:active { box-shadow: none; }
button.link.danger, button.link .danger { color: var(--danger); }
button.link.danger:hover { background: color-mix(in srgb, var(--danger) 12%, transparent); color: var(--danger); }

/* ---- form layouts ---- */

.row-form { display: flex; gap: 8px; align-items: flex-end; flex-wrap: wrap; }
/* Тільки прямі діти: у label головна вісь — колонка, тож flex-basis там став би
   ВИСОТОЮ поля, і select виростав би на 140px. */
.row-form > input, .row-form > select, .row-form > label { flex: 1 1 150px; min-width: 0; }
.row-form > label { display: flex; flex-direction: column; }
.row-form label > * { flex: none; }
.row-form button, .row-form .quiet { flex: none; }
.row-form > .grow, .row-form label.grow { flex: 1 1 260px; }
/* Протилежність `.grow`: поле, яке НЕ має рости. Кожен прямий інпут у .row-form
   має `flex-grow: 1`, тож єдиний інпут у ряду забирав усю ширину — «Нове
   значення» довідника й «Назва групи» розтягувались на 1030px під два слова. */
.row-form > .lim, .row-form label.lim { flex: 0 1 360px; }

.inline { display: flex; gap: 8px; align-items: center; margin: 0; }
/* `text-align: right` на комірці не рухає флекс-дитину: заголовок «Дія» стояв
   праворуч, а сама кнопка — ліворуч, посеред порожньої колонки. */
td.right > .inline, td.right > form, th.right > .inline { justify-content: flex-end; }

/* 240px, не 190: у `.page.wide` при 190 виходило шість однакових колонок, і
   «Валюта» з трьох літер займала рівно стільки ж, скільки select із повною
   назвою договору — яка потім і обрізалася. Колонок стало менше й вони ширші;
   що не влазить — бере .span-2 або .wide. */
.grid-form {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
	gap: 14px 12px;
	align-items: end;
}

.grid-form button { justify-self: start; }
.grid-form .wide { grid-column: 1 / -1; }
.grid-form .span-2 { grid-column: span 2; }

/* Підказка під полем НЕ живе всередині <label>. `align-items: end` вирівнює
   контроли по низу клітинки, тож текст під полем піднімав саме́ поле — і ряд із
   трьох полів отримував три різні висоти підпису (видно було на /bill/{id}:
   277 / 296 / 297px). Хінт — окремий елемент на весь ряд, під ним. */
.grid-form > .form-hint {
	grid-column: 1 / -1;
	margin: -8px 0 0;
	font-size: 12px;
	line-height: 1.4;
	color: var(--text-dim);
}

fieldset {
	border: 1px solid var(--border);
	border-radius: var(--radius);
	padding: 6px 14px 14px;
	grid-column: 1 / -1;
	min-width: 0;
	margin: 0;
}

legend { font-size: 12px; font-weight: 600; letter-spacing: .02em; text-transform: uppercase; color: var(--text-dim); padding: 0 6px; }

.chk {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	min-height: var(--control-h);
	color: var(--text);
	font-size: 14px;
	font-weight: 400;
	margin-right: 14px;
	cursor: pointer;
}

.chk input { width: 16px; margin: 0; }

.form-actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }

/* Липкий низ довгої форми — і тільки там, де форма справді довга: ряд дій, що
   завершує <form> на рівні сторінки. «Зберегти» стояло за півтори тисячі
   пікселів прокрутки від «Скасувати» вгорі справа — дві дії однієї форми на
   різних кінцях сторінки. Ряди дій усередині картки (замінити файл, додати
   платіж) лишаються на місці: там нема чого прокручувати. */
.page > form > .form-actions:last-child {
	position: sticky;
	bottom: 0;
	z-index: 5;
	margin-top: 4px;
	padding: 12px var(--gap);
	background: color-mix(in srgb, var(--surface) 92%, transparent);
	backdrop-filter: blur(8px);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	box-shadow: var(--shadow-md);
}

/* Групи чекбоксів (Теги, Дозволи, Індивідуальна група) розкладалися
   `margin-right: 14px` + перенос, тому другий ряд не ставав під перший. */
.chk-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 4px 12px; }
.chk-grid .chk { margin-right: 0; }

/* Пара «години : хвилини» — це одне значення, а не два поля. У гріді форми вони
   опинялися в різних рядах, і «3» та «15» читалися як незв'язані числа. */
.pair { display: flex; align-items: end; gap: 8px; }
.pair > label { flex: 1 1 0; min-width: 0; }
.pair .pair-sep { padding-bottom: 9px; color: var(--text-dim); }

/* Посилання «назад» у шапці підсторінки. */
.back { align-self: center; }

.members { display: flex; flex-wrap: wrap; gap: 8px 0; align-items: center; }
.members button { margin-left: auto; }

/* Нотатки. Список абзаців, не таблиця — у нотатки немає колонок. Форму
   редагування розкриває рідний <details>, тож JS тут нуль. */
.note-list { list-style: none; margin: var(--gap) 0 0; padding: 0; }
.note-list > li { padding: 12px 0; border-top: 1px solid var(--border); }
.note-list > li > .sub-line { margin: 0 0 4px; }
.note-list > li > .notes { margin: 0 0 6px; }
.note-list summary { cursor: pointer; font-size: 13px; color: var(--text-dim); }
.note-list summary:hover { color: var(--accent); }
.note-list details[open] summary { margin-bottom: 8px; }

/* ============================================================================
   Cards
   ========================================================================= */

.card {
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	padding: var(--gap);
	box-shadow: var(--shadow-sm);
	min-width: 0;
}

.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: var(--gap); }

.link-card {
	display: flex; flex-direction: column; gap: 4px;
	text-decoration: none; color: var(--text);
	transition: border-color .12s var(--ease), box-shadow .12s var(--ease), transform .12s var(--ease);
}
.link-card:hover {
	border-color: var(--accent);
	box-shadow: var(--shadow-md);
	transform: translateY(-1px);
	color: var(--text);
}

.card-head {
	display: flex;
	align-items: center;
	gap: 10px;
	flex-wrap: wrap;
	margin-bottom: 12px;
	min-height: 26px;
}
.card-head .sub { margin-top: 1px; }
.card-head form, .card-head > a.btn, .card-head > .quiet { margin-left: auto; }

.empty {
	color: var(--text-dim);
	padding: 22px 24px;
	text-align: center;
	font-size: 14px;
}

/* Порожня СЕКЦІЯ — це рядок, а не блок на 165px: у Корзині таких десять поспіль,
   і сторінка була майже цілком з порожнечі. Клас явний, бо структурно
   («єдиний .empty в картці») секція Корзини не відрізняється від порожнього
   стану цілої сторінки, а той навпаки має лишитись великим і по центру. */
.empty.compact { padding: 2px 0 0; text-align: left; }

details.card summary {
	cursor: pointer;
	font-weight: 600;
	list-style-position: outside;
	border-radius: var(--radius-sm);
}
details.card[open] summary { margin-bottom: 14px; }

.stack { display: flex; flex-direction: column; gap: var(--gap); }
/* `stretch`, не `start`: дві картки в ряду мають закінчуватися на одній лінії.
   При `start` «Інформація» була 438px, а «Контактні дані» поруч — 366px. */
.cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--gap); align-items: stretch; }
.record .card + .card, .stack > .card + .card { margin-top: 0; }

/* ============================================================================
   Page head, tabs, filters
   ========================================================================= */

.page-head { display: flex; align-items: center; gap: 12px var(--gap); flex-wrap: wrap; }
.page-head h1 { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; min-width: 0; }
.record-id { min-width: 0; display: flex; flex-direction: column; gap: 4px; }

.page-actions {
	margin-left: auto;
	display: flex;
	align-items: center;
	gap: 8px;
	flex-wrap: wrap;
}
.page-actions form { margin: 0; display: flex; align-items: center; gap: 8px; }
/* Деструктивна дія не стоїть впритул до синьої: між ними роздільник, щоб
   «Видалити» не ловилося промахом по «Редагувати». */
.page-actions > form:has(button.link.danger), .page-actions > button.link.danger, .page-actions > .danger {
	margin-left: 4px;
	padding-left: 14px;
	border-left: 1px solid var(--border);
}

.tabs {
	display: flex;
	flex-wrap: wrap;
	gap: 2px;
	border-bottom: 1px solid var(--border);
}

.tabs a {
	display: inline-flex;
	align-items: center;
	height: 38px;
	padding: 0 12px;
	text-decoration: none;
	color: var(--text-dim);
	border-bottom: 2px solid transparent;
	margin-bottom: -1px;
	font-size: 14px;
	font-weight: 500;
	border-radius: var(--radius-sm) var(--radius-sm) 0 0;
	transition: color .12s var(--ease), background .12s var(--ease);
}

.tabs a:hover { color: var(--text); background: var(--surface-2); }
/* Вага не змінюється: жирніший текст ширший, і вкладка стрибала б при виборі.
   Стан показують колір і смужка знизу. Те саме в .seg. */
/* Фон такий самий, як у :hover: після переходу курсор стоїть нерухомо над новим
   елементом, тож :hover до нього ще не застосовано — без цього рядка вкладка
   на мить блимала порожнім тлом. */
.tabs a[aria-selected="true"] { color: var(--text); background: var(--surface-2); border-bottom-color: var(--accent); }
/* Скільки записів за вкладкою. Без цього вкладку відкривають, щоб побачити, що
   вона порожня. Пігулка, а не «(3)» у дужках: інакше воно читалося б як частина
   назви й переносилось разом із нею. */
.tab-n {
	margin-left: 7px;
	padding: 0 6px;
	min-width: 18px;
	height: 18px;
	display: inline-flex; align-items: center; justify-content: center;
	font-size: 11px; font-weight: 600;
	color: var(--text-dim);
	background: var(--surface-3);
	border-radius: 999px;
}
.tabs a[aria-selected="true"] .tab-n { background: var(--accent-soft); color: var(--accent); }

.tabs-spacer { flex: 1; }

/* Flex, а не `grid auto-fit`. Грід давав УСІМ полям однакову ширину незалежно
   від змісту: на /calendar і /contracts, де фільтрів два-три, `<select>` зі
   словом «Усі» роздувався до 480px, а «Застосувати/Скинути» падали у випадкову
   клітинку або на власний ряд. Тепер поле має ширину за змістом, рости має
   право лише пошук (.grow), а дії завжди стоять на правому краю останнього ряду. */
.filters {
	display: flex;
	flex-wrap: wrap;
	gap: 14px 12px;
	align-items: end;
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	box-shadow: var(--shadow-sm);
	padding: var(--gap);
}

.filters > label { flex: 0 1 200px; min-width: 0; }
.filters > label.span-2 { flex: 0 1 300px; }
.filters > label.grow   { flex: 1 1 240px; }
.filters > label.wide   { flex: 1 1 100%; }
/* Чекбокс серед фільтрів («Прострочені») — за змістом, а не в колонку на 200px. */
.filters > .chk { flex: none; margin-right: 0; }

.filter-actions { display: flex; align-items: flex-end; gap: 8px; margin-left: auto; flex: none; }

.banner {
	background: color-mix(in srgb, var(--warn) 15%, var(--surface));
	border: 1px solid color-mix(in srgb, var(--warn) 35%, transparent);
	border-radius: var(--radius-sm);
	padding: 10px 14px; margin: 0; font-size: 14px;
}

.error {
	background: color-mix(in srgb, var(--danger) 12%, var(--surface));
	border: 1px solid color-mix(in srgb, var(--danger) 32%, transparent);
	color: var(--danger);
	border-radius: var(--radius-sm);
	padding: 9px 12px;
	font-size: 13px;
	margin: 0;
}

/* ============================================================================
   Одночасна робота
   ========================================================================= */

/* Смужка «дані змінилися». Живе поза #main — саме #main і підміняється. */
.live-bar {
	flex: none;
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 8px var(--gap);
	font-size: 13px;
	background: color-mix(in srgb, var(--accent) 10%, var(--surface));
	border-bottom: 1px solid color-mix(in srgb, var(--accent) 28%, transparent);
	position: sticky;
	top: var(--topbar-h);
	z-index: 19;
}
.live-bar[hidden] { display: none; }
.live-bar button { margin-left: auto; }

/* Банер конфлікту: по рядку на кожне поле, яке правили обидва. */
.conflict {
	background: color-mix(in srgb, var(--warn) 13%, var(--surface));
	border: 1px solid color-mix(in srgb, var(--warn) 35%, transparent);
	border-radius: var(--radius-sm);
	padding: 10px 14px;
	font-size: 13px;
}
/* Деякі форми — грід (.grid-form): банер має займати весь ряд, а не одну колонку. */
.grid-form > .conflict { grid-column: 1 / -1; }
.conflict > p { margin: 0 0 8px; }
.conflict ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.conflict li { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.conflict b { font-weight: 650; }
.conflict .val {
	font-family: var(--mono, ui-monospace, monospace);
	background: var(--surface-2);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	padding: 1px 6px;
	max-width: 40ch;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.conflict li.taken { opacity: .55; }
.conflict li.taken button { display: none; }

/* ============================================================================
   Tables
   ========================================================================= */

table {
	width: 100%;
	border-collapse: separate;
	border-spacing: 0;
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	box-shadow: var(--shadow-sm);
	overflow: hidden;
}

th, td {
	text-align: left;
	padding: 10px 14px;
	border-bottom: 1px solid var(--border);
	vertical-align: middle;
}

/* `white-space: normal`, а не `nowrap`. Саме nowrap робив так, що ширину колонки
   диктував ЗАГОЛОВОК, а не дані: «ВІДПОВІДАЛЬНИЙ ЗА КЛІЄНТА» забирав 242px під
   імена по 90px, а «Назва» лишалася з 270px і переносилась у три рядки. */
th {
	font-size: 11px;
	text-transform: uppercase;
	letter-spacing: .04em;
	color: var(--text-dim);
	font-weight: 650;
	background: var(--surface-2);
	white-space: normal;
	text-wrap: balance;
}

tbody tr:last-child td { border-bottom: none; }
tbody tr { transition: background .1s var(--ease); }
tbody tr:hover { background: var(--surface-2); }

/* Wide tables scroll inside the card, never the page.
   Колонка «Назва» не має їхати геть — по ній і впізнають рядок. */
.table-wrap {
	overflow-x: auto;
	border-radius: var(--radius);
	overscroll-behavior-x: contain;

	/* Смуга прокрутки видима **завжди**, а не лише під час руху.
	   Це і є та сама «немає підказки, що таблиця їде вбік»: macOS ховає
	   накладні смуги до першого дотику, тож про десять колонок праворуч ніхто
	   не здогадувався. `scrollbar-width: thin` вмикає постійну смугу і в
	   Chrome, і в Safari 18+, і у Firefox — одним рядком і без JS.
	   ponytail: класичний трюк із чотирма градієнтами тут не працює — липка
	   перша колонка і шапка непрозорі й затуляють тінь. Якщо колись знадобиться
	   саме тінь — це `animation-timeline: scroll(self inline)` під @supports. */
	scrollbar-width: thin;
	scrollbar-color: var(--border-strong) transparent;
	padding-bottom: 2px;

	/* Клавіатурний фокус не має ховатися під липкою першою колонкою. */
	scroll-padding-inline-start: 220px;
}
.table-wrap::-webkit-scrollbar { height: 10px; }
.table-wrap::-webkit-scrollbar-track { background: transparent; }
.table-wrap::-webkit-scrollbar-thumb {
	background: var(--border-strong);
	border: 3px solid var(--surface);
	border-radius: 6px;
}
.table-wrap::-webkit-scrollbar-thumb:hover { background: var(--text-mute); }
/* Колонки беруть свою природну ширину; коли всім разом не вистачає місця, вони
   стискаються ПРОПОРЦІЙНО (найширша віддає найбільше) — і лише коли кожна вже
   на своєму мінімумі, таблиця починає скролитись.
   Раніше `max-width` тут не було, тож найширша колонка забирала свою стелю
   цілком, а решта виштовхувалась за край: на /tasks сім колонок просили 1469px
   у контейнер 1229px, хоча вміст спокійно влазив. */
.table-wrap table {
	width: max-content;
	min-width: 100%;
	max-width: 100%;
	border-radius: var(--radius) 0 0 var(--radius);
}
/* Підлога, нижче якої стиснути не можна: без неї «Дата» могла б з'їхати в
   «01.08.» + перенос, а це вже не читається. */
table.list th, table.list td { min-width: 84px; }
table.list th.nowrap, table.list td.nowrap { min-width: max-content; }

table.list th, table.list td { vertical-align: top; max-width: 320px; }
table.list td { line-height: 1.4; }
/* Підкреслені посилання в кожній комірці роблять таблицю смугастою — лишаємо
   підкреслення тільки на наведенні. */
table.list td a { text-decoration: none; }
table.list td a:hover { text-decoration: underline; }

/* ---- клік по всьому рядку ----
   <tr> не буває посиланням, тому посилання назви розтягується на весь рядок
   псевдоелементом. У рядку 80px висоти клікабельною була смужка тексту у 20px.
   Вкладені посилання (клієнт, справа) підіймаються над ним і ведуть куди вели. */
table.list tbody tr { position: relative; }
table.list td.sticky a.strong::after { content: ''; position: absolute; inset: 0; }
table.list td a:not(.strong), table.list td button, table.list td form { position: relative; z-index: 1; }

table.list th.sticky, table.list td.sticky {
	position: sticky;
	left: 0;
	background: var(--surface);
	/* Найважливіша колонка має бути найширшою, а не найвужчою. */
	min-width: 260px;
	max-width: 440px;
	z-index: 0;
	/* Не просто лінія, а підняття: так одразу видно, що решта колонок їде під
	   цю, а не обривається на ній. */
	box-shadow: 1px 0 0 var(--border), 8px 0 8px -8px var(--shadow-2);
}

/* ---- сортування ----
   Заголовок-посилання займає всю комірку, щоб ціль була висотою з рядок шапки. */
table.list th a {
	display: flex;
	align-items: center;
	gap: 4px;
	margin: -10px -14px;
	padding: 10px 14px;
	color: inherit;
	text-decoration: none;
}
table.list th a:hover { color: var(--text); background: var(--surface-3); }
/* Стрілка мовчить, поки колонка не активна: вісім однакових ↕ у шапці — це шум,
   який читається як прикраса, а не як «сюди можна натиснути». */
table.list th a::after { content: '↕'; opacity: 0; font-size: 10px; transition: opacity .12s var(--ease); }
table.list th a:hover::after, table.list th:focus-within a::after { opacity: .45; }
table.list th[aria-sort] a { color: var(--text); }
table.list th[aria-sort="ascending"]  a::after { content: '↑'; opacity: 1; color: var(--accent); }
table.list th[aria-sort="descending"] a::after { content: '↓'; opacity: 1; color: var(--accent); }

/* ---- пріоритет колонок ----
   Колонки, які на реальних даних майже завжди «—» або дублюють сусідню, з'їдали
   ширину і виштовхували таблицю за край. Коли місця мало — вони зникають; дані
   від того не пропадають, вони є на сторінці запису.

   @container, а не @media: медіазапит міряє ВІКНО, а місце під таблицю дає
   контейнер. На 1512-му ноутбуці вікно 1512, а `.table-wrap` — 1229 (мінус меню
   й відступи), тож будь-який поріг у @media або спрацьовував зарано на
   зовнішньому моніторі, або не спрацьовував тут. Скрол лишається чесним
   запасним варіантом для справді широких списків, а не звичайним станом. */
.table-wrap { container-type: inline-size; }
@container (max-width: 1300px) {
	table.list .col-lo { display: none; }
}
/* Липка колонка з коротким значенням (номер інвойса) — 260px під «1» це діра. */
table.list th.sticky.tight, table.list td.sticky.tight { min-width: 110px; }
table.list th.sticky { z-index: 1; background: var(--surface-2); }
table.list tbody tr:hover td.sticky { background: var(--surface-2); }

table.list td.num, table.list th.num { text-align: right; white-space: nowrap; }
table.list th.num a { justify-content: flex-end; }
table.list tfoot td { font-weight: 650; border-top: 2px solid var(--border-strong); background: var(--surface-2); }
table.list tfoot td.sticky { background: var(--surface-2); }

/* Підсумок під таблицею стоїть на правому краю картки — тобто під колонкою
   «Сума», яку він підсумовує. Як `.facts` він починався на лівому краю, а
   колонка з числами закінчувалась за тисячу пікселів праворуч. */
.sum-up {
	display: grid;
	grid-template-columns: 1fr auto;
	gap: 6px 24px;
	width: min(360px, 100%);
	margin: 14px 0 0 auto;
	font-size: 14px;
}
.sum-up dt { color: var(--text-dim); }
.sum-up dd { margin: 0; text-align: right; white-space: nowrap; }
.sum-up .sum-total {
	padding-top: 8px;
	margin-top: 2px;
	border-top: 1px solid var(--border-strong);
	font-weight: 650;
	color: var(--text);
	font-size: 15px;
}

.pager { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pager .sub { margin-right: auto; }

ul.plain { list-style: none; margin: 0; padding: 0; }

ul.relations { list-style: none; margin: 0 0 12px; padding: 0; }
ul.relations li {
	display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
	padding: 8px 0; border-bottom: 1px solid var(--border);
	min-height: 40px;
}
ul.relations li:last-child { border-bottom: none; }
ul.relations form { margin-left: auto; }

/* Стеля обов'язкова: у картці на 1230px пара «Метод тарифікації / —» розтягувала
   значення на 1100px порожнечі. Значення має стояти ПОРУЧ із підписом, а зайва
   ширина картки лишається полем, а не діркою. */
.facts { display: grid; grid-template-columns: minmax(120px, auto) minmax(0, 1fr); gap: 8px 16px; margin: 0 0 12px; align-items: baseline; max-width: 620px; }
.facts dt { color: var(--text-dim); font-size: 13px; }
.facts dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.facts:last-child { margin-bottom: 0; }

/* Довгий список фактів (Умови оплати — вісім рядків) у широкій картці стає
   двома колонками пар замість однієї колонки з піврядка тексту. */
.facts.pairs {
	max-width: none;
	grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
	column-gap: 32px;
}
.facts.pairs > div { display: grid; grid-template-columns: minmax(120px, auto) minmax(0, 1fr); gap: 8px 16px; align-items: baseline; }

/* ============================================================================
   Badges
   ========================================================================= */

.tags { display: inline-flex; flex-wrap: wrap; gap: 4px; vertical-align: middle; }

.tag {
	display: inline-flex; align-items: center;
	height: 20px;
	font-size: 11px;
	padding: 0 8px;
	border-radius: 999px;
	background: var(--surface-2);
	border: 1px solid var(--border);
	color: var(--text-dim);
	white-space: nowrap;
}

.lock {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	height: 20px;
	font-size: 11px;
	padding: 0 8px 0 6px;
	border-radius: 999px;
	background: color-mix(in srgb, var(--warn) 16%, var(--surface));
	border: 1px solid color-mix(in srgb, var(--warn) 32%, transparent);
	color: var(--text);
	cursor: help;
	white-space: nowrap;
}

.lock svg { width: 12px; height: 12px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.8; }

/* Довгі назви ad-hoc груп («Контакт #5 (…)») — деталь у тайтлі. */
table.list .lock-name { display: block; max-width: 170px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Статус несе колір І текст, ніколи сам колір. */
.status {
	display: inline-flex; align-items: center;
	height: 21px;
	font-size: 11.5px; font-weight: 550;
	padding: 0 9px;
	border-radius: 999px;
	white-space: nowrap;
	border: 1px solid;
}
.status-active  { color: var(--ok);    border-color: color-mix(in srgb, var(--ok) 42%, transparent);   background: color-mix(in srgb, var(--ok) 10%, transparent); }
.status-pending { color: var(--warn);  border-color: color-mix(in srgb, var(--warn) 42%, transparent); background: color-mix(in srgb, var(--warn) 10%, transparent); }
.status-closed  { color: var(--text-dim); border-color: var(--border); background: var(--surface-2); }

.status-todo      { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 42%, transparent); background: var(--accent-soft); }
.status-review    { color: var(--warn);  border-color: color-mix(in srgb, var(--warn) 42%, transparent); background: color-mix(in srgb, var(--warn) 10%, transparent); }
.status-done      { color: var(--ok);    border-color: color-mix(in srgb, var(--ok) 42%, transparent);   background: color-mix(in srgb, var(--ok) 10%, transparent); }
.status-cancelled { color: var(--text-dim); border-color: var(--border); background: var(--surface-2); text-decoration: line-through; }

/* Тип і пріоритет: колір — оздоба, слово — інформація. */
.kind {
	display: inline-flex; align-items: center;
	height: 20px;
	font-size: 11.5px;
	padding: 0 8px;
	border-radius: 4px;
	background: var(--surface-2);
	border-left: 3px solid var(--border);
	white-space: nowrap;
}
.kind-task    { border-left-color: var(--accent); }
.kind-event   { border-left-color: var(--ok); }
.kind-hearing { border-left-color: var(--danger); }
.kind-time    { border-left-color: var(--accent); }
.kind-expense { border-left-color: var(--warn); }

/* Тіло листа. `pre-wrap`, а не `pre`: текст прийшов ззовні й буває з рядками
   на 300 символів, які інакше розтягнули б сторінку вбік. */
.mail-body {
	white-space: pre-wrap;
	overflow-wrap: anywhere;
	font: inherit;
	margin: 0;
	max-height: 60vh;
	overflow-y: auto;
}
/* HTML-версія — у sandbox-iframe, тож своїх токенів вона не бачить і не має. */
.mail-html {
	width: 100%; height: 50vh;
	margin-top: 10px;
	border: 1px solid var(--border);
	border-radius: 6px;
	background: #fff;
	color-scheme: light;
}

/* Оплачуваність — колір і текст, ніколи сам колір. */
.bill { font-size: 12px; }
.bill-yes { color: var(--ok); }
.bill-no  { color: var(--text-dim); }

.prio { font-size: 12px; color: var(--text-dim); }
.prio-high { color: var(--danger); font-weight: 650; }
.overdue { color: var(--danger); font-weight: 650; }

/* W.I.P. — одна колонка на валюту, суми різних валют не додаються. */
.totals { display: flex; flex-wrap: wrap; gap: var(--gap); }
/* `flex: 1 1` замість голого `min-width`: одна валюта в картці на 1230px давала
   коробку 260px і три чверті порожнечі. Стеля 420px — щоб при одній валюті
   підсумок не розтягнувся на всю картку й підпис не втік від числа. */
.total {
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	box-shadow: var(--shadow-sm);
	padding: 14px 16px;
	flex: 1 1 260px;
	min-width: 260px;
	max-width: 420px;
}
/* Усередині картки рамки не треба — це була картка в картці, з подвійним
   контуром і 810px порожнечі праворуч. Тут підсумок просто зміст картки. */
.card > .totals > .total {
	border: 0; box-shadow: none; background: none;
	padding: 0; max-width: none; min-width: 0;
}
.total-ccy { font-size: 11px; font-weight: 650; color: var(--text-dim); letter-spacing: .08em; }
.total .facts { margin: 8px 0 0; gap: 5px 16px; }

/* ============================================================================
   Auth
   ========================================================================= */

body.centered {
	display: grid;
	place-items: center;
	min-height: 100vh;
	padding: var(--gap);
}

.signin { width: min(370px, 100%); display: flex; flex-direction: column; gap: 14px; }
/* Той самий .brand, що в шапці, — лише без висоти топбару й лінії під ним. */
.signin h1.brand { justify-content: center; height: auto; padding: 0; border: 0; }
.signin .sub { text-align: center; }
.signin button { width: 100%; }

/* ============================================================================
   Command palette
   ========================================================================= */

dialog#palette {
	width: min(560px, 92vw);
	margin-top: 12vh;
	padding: 0;
	border: 1px solid var(--border);
	border-radius: var(--radius-lg);
	background: var(--surface);
	color: var(--text);
	box-shadow: var(--shadow-lg);
}

dialog#palette::backdrop { background: var(--backdrop); backdrop-filter: blur(2px); }

dialog#palette input {
	border: none;
	border-bottom: 1px solid var(--border);
	border-radius: var(--radius-lg) var(--radius-lg) 0 0;
	height: 52px;
	padding: 0 16px;
	font-size: 15px;
	background: none;
}
dialog#palette input:focus { box-shadow: none; }

dialog#palette ul { list-style: none; margin: 0; padding: 6px; max-height: 46vh; overflow-y: auto; }

/* Тип у своїй колонці, назва й підпис — у другій. Тип несе кожен рядок, тому
   заголовків груп немає: список лишається пласким, а стрілки — простими. */
dialog#palette li {
	display: grid;
	grid-template-columns: 84px 1fr;
	align-items: baseline;
	column-gap: 10px;
	padding: 8px 12px;
	border-radius: var(--radius-sm);
	cursor: pointer;
	font-size: 14px;
}

dialog#palette li .type {
	font-size: 11px;
	color: var(--text-mute);
	text-align: right;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

dialog#palette li .label,
dialog#palette li .sub {
	grid-column: 2;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

dialog#palette li .sub { font-size: 12px; color: var(--text-mute); }

dialog#palette li[aria-selected="true"] { background: var(--accent-soft); color: var(--accent); }
dialog#palette li[aria-selected="true"] .type,
dialog#palette li[aria-selected="true"] .sub { color: inherit; opacity: .7; }

dialog#palette .hint {
	margin: 0;
	padding: 9px 14px;
	border-top: 1px solid var(--border);
	font-size: 12px;
	color: var(--text-mute);
}

/* ============================================================================
   Канбан
   ========================================================================= */

.board { display: grid; grid-template-columns: repeat(4, minmax(210px, 1fr)); gap: 12px; align-items: start; }

.board-col {
	background: var(--surface-2);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	padding: 10px;
	min-width: 0;
}

.board-col h2 { display: flex; align-items: center; gap: 8px; font-size: 13px; text-transform: uppercase; letter-spacing: .03em; color: var(--text-dim); margin: 0 0 10px; }
.board-col h2 .sub { margin-left: auto; font-size: 12px; }

.board-drop { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; min-height: 60px; }
.board-drop.over { outline: 2px dashed var(--accent); outline-offset: 4px; border-radius: var(--radius-sm); }

.board-card {
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	box-shadow: var(--shadow-sm);
	padding: 9px 11px;
	cursor: grab;
	display: flex;
	flex-direction: column;
	/* Інакше пігулка «Кримінальна практика» розтягується на всю картку. */
	align-items: flex-start;
	gap: 4px;
}
.board-card > * { max-width: 100%; }
.board-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); }
.board-card.dragging { opacity: .4; }
.board-card .kind { padding: 0 6px; }

/* ============================================================================
   Календар
   ========================================================================= */

.cal {
	display: grid;
	grid-template-columns: repeat(7, minmax(0, 1fr));
	gap: 1px;
	background: var(--border);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	box-shadow: var(--shadow-sm);
	overflow: hidden;
}

.cal-head {
	background: var(--surface-2);
	padding: 8px;
	font-size: 11px;
	font-weight: 650;
	text-transform: uppercase;
	letter-spacing: .04em;
	color: var(--text-dim);
}

.cal-day {
	background: var(--surface);
	min-height: 110px;
	padding: 5px;
	display: flex;
	flex-direction: column;
	gap: 3px;
	min-width: 0;
}

.cal-week .cal-day { min-height: 320px; }
.cal-day.muted   { background: var(--bg); }
.cal-day.weekend { background: color-mix(in srgb, var(--surface-2) 55%, var(--surface)); }
.cal-day.today   { box-shadow: inset 0 0 0 2px var(--accent); }
.cal-day.muted .cal-num { color: var(--text-mute); }

.cal-num {
	align-self: flex-start;
	display: inline-flex; align-items: center; justify-content: center;
	min-width: 22px; height: 22px;
	font-size: 12px;
	color: var(--text-dim);
	text-decoration: none;
	border-radius: 999px;
}
.cal-num:hover { background: var(--surface-3); color: var(--accent); }
.cal-day.today .cal-num { background: var(--accent); color: var(--accent-fg); font-weight: 650; }

.cal-item {
	display: block;
	font-size: 12px;
	line-height: 1.4;
	padding: 3px 6px;
	border-radius: 4px;
	background: var(--surface-2);
	border-left: 3px solid var(--border);
	color: var(--text);
	text-decoration: none;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.cal-item:hover { background: color-mix(in srgb, var(--accent) 14%, var(--surface-2)); color: var(--text); }
.cal-item.done  { opacity: .5; text-decoration: line-through; }

/* ============================================================================
   Дашборд + звіти
   ========================================================================= */

.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; }

.tile {
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	box-shadow: var(--shadow-sm);
	padding: 14px var(--gap);
	display: flex;
	flex-direction: column;
	gap: 3px;
	text-decoration: none;
	color: var(--text);
	transition: border-color .12s var(--ease), box-shadow .12s var(--ease), transform .12s var(--ease);
}
a.tile:hover { border-color: var(--accent); box-shadow: var(--shadow-md); transform: translateY(-1px); color: var(--text); }
.tile-n { font-size: 27px; font-weight: 650; letter-spacing: -.02em; line-height: 1.15; }
.tile-u { font-size: 14px; font-weight: 500; color: var(--text-dim); margin-left: 5px; }
.tile.bad .tile-n { color: var(--danger); }

.step {
	display: inline-grid;
	place-items: center;
	width: 22px; height: 22px;
	flex: none;
	border-radius: 50%;
	background: var(--accent-soft);
	border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
	font-size: 11px;
	font-weight: 650;
	color: var(--accent);
}

.report-picker { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 10px; }

.report-card {
	display: flex;
	flex-direction: column;
	gap: 4px;
	padding: 13px;
	border: 1px solid var(--border);
	border-radius: var(--radius);
	text-decoration: none;
	color: var(--text);
	transition: border-color .12s var(--ease), background .12s var(--ease), box-shadow .12s var(--ease);
}
.report-card:hover { border-color: var(--accent); box-shadow: var(--shadow-sm); color: var(--text); }
.report-card.on { border-color: var(--accent); background: var(--accent-soft); box-shadow: 0 0 0 1px var(--accent) inset; }

/* ponytail: єдина «діаграма» — смужка під числом. SVG чи бібліотека тут нічого
   не додають: у звіті важливе число, смужка лише дає око зачепитися. */
.bar {
	display: inline-block;
	/* Фіксована ширина: інакше смужка міряє довжину числа, а не саме число. */
	min-width: 62px;
	padding: 2px 7px;
	border-radius: 4px;
	text-align: right;
	background: linear-gradient(to right,
		color-mix(in srgb, var(--accent) 26%, transparent) var(--v, 0%),
		var(--surface-2) var(--v, 0%));
}

/* У `.facts` (Утилізація на дашборді) смужка на 62px під значенням «1 %»
   читалася як зламане поле вводу. У списку фактів вона займає свою колонку. */
.facts .bar { display: block; min-width: 0; }

.report-note { margin: 12px 0 0; }

/* ============================================================================
   Друкований документ (рахунок на оплату / акт)
   ========================================================================= */

/* Це бланк, а не картка застосунку: власна розмітка, щоб на папері не
   доводилося скасовувати десяток правил .card. На екрані рамка натякає на
   аркуш, у друці її прибирає блок нижче. */
.doc {
	max-width: 760px;
	margin-inline: auto;
	padding: 26px 30px;
	border: 1px solid var(--border);
	border-radius: var(--radius);
	background: var(--surface);
	line-height: 1.45;
}

.doc-draft {
	margin: 0 0 12px;
	padding: 9px 12px;
	border-radius: var(--radius);
	border: 1px solid color-mix(in srgb, var(--warn) 45%, transparent);
	background: color-mix(in srgb, var(--warn) 10%, transparent);
	font-size: 13px;
}

.doc-title {
	margin: 0 0 18px;
	padding-bottom: 12px;
	border-bottom: 2px solid var(--border-strong);
	font-size: 20px;
	text-align: center;
}

.doc-parties {
	display: grid;
	grid-template-columns: max-content 1fr;
	gap: 5px 16px;
	margin: 0 0 20px;
	font-size: 14px;
}
.doc-parties dt { color: var(--text-mute); }
.doc-parties dd { margin: 0; }

.doc-lines { width: 100%; border-collapse: collapse; font-size: 14px; }
/* Списки застосунку пишуть заголовок капсом; бланк — ні: «ВСЬОГО ДО СПЛАТИ»
   в підсумку читається як крик, а не як документ. */
.doc-lines th, .doc-lines td {
	padding: 6px 8px;
	border: 1px solid var(--border);
	vertical-align: top;
	text-transform: none;
	letter-spacing: normal;
	font-size: inherit;
	color: inherit;
}
.doc-lines thead th { background: var(--surface-2); font-weight: 600; text-align: left; }
.doc-lines .right { text-align: right; white-space: nowrap; }
.doc-lines tfoot th { text-align: right; font-weight: 500; border-left: none; }
.doc-lines tfoot .doc-total th, .doc-lines tfoot .doc-total td { font-weight: 700; font-size: 15px; }

.doc-words { margin: 12px 0 0; font-style: italic; }
.doc-note  { margin: 12px 0 0; font-size: 13px; color: var(--text-dim); }
.doc-free  { white-space: pre-line; }

.doc-sign {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
	gap: 12px 30px;
	margin: 36px 0 0;
	font-size: 14px;
}
.doc-sign > div { display: grid; grid-template-columns: max-content 1fr; gap: 2px 10px; align-items: end; }
.doc-role { color: var(--text-mute); }
/* Порожня лінія під підпис — саме те, що ручка шукає на папері. */
.doc-line { border-bottom: 1px solid var(--text); height: 1.3em; }
.doc-who  { grid-column: 2; font-size: 12px; color: var(--text-mute); }
.doc-mp   { grid-column: 1 / -1; margin-top: 6px; color: var(--text-mute); font-size: 12px; }

/* ============================================================================
   Друк
   ========================================================================= */

@media print {
	/* Папір завжди білий. `color-scheme: light` вимикає темні значення в усіх
	   light-dark() токенах одним рядком; далі лише прибираємо кольори, які на
	   ч/б принтері зливаються. */
	:root, :root[data-theme="dark"], :root[data-theme="light"] {
		color-scheme: light;
		--bg:        #ffffff;
		--surface:   #ffffff;
		--surface-2: #ffffff;
		--surface-3: #ffffff;
		--border:    #999999;
		--border-strong: #666666;
		--text:      #000000;
		--text-dim:  #444444;
		--text-mute: #666666;
		--accent:    #000000;
		--accent-soft: transparent;
		--danger:    #000000;
		--ok:        #000000;
		--warn:      #000000;
		--shadow-sm: none;
		--shadow-md: none;
		--shadow-lg: none;
	}

	.sidebar, .topbar, .no-print, .page-actions, .skip, .pager, .nav-toggle { display: none !important; }
	.shell, .content, main { display: block; padding: 0; margin: 0; }
	.page { max-width: none; }
	.card, .tile, .total { border: none; padding: 0 0 12px; break-inside: avoid; box-shadow: none; }
	.table-wrap { overflow: visible; }
	.table-wrap table { min-width: 0; }
	table, table.list { border-collapse: collapse; box-shadow: none; }
	table.list td.sticky, table.list th.sticky { position: static; box-shadow: none; }
	table.list tfoot td, th { background: none; }
	.bar { background: none; padding: 0; min-width: 0; }
	a { text-decoration: none; }

	@page { size: A4; margin: 14mm; }

	/* На папері аркуш і є рамкою. Таблиця може ламатися між сторінками, а от
	   підписи й підсумок під ними — ні. */
	.doc { max-width: none; padding: 0; border: none; }
	.doc-lines thead { display: table-header-group; }
	.doc-lines tr { break-inside: avoid; }
	.doc-sign { break-inside: avoid; }
}

/* ============================================================================
   Адаптив
   ========================================================================= */

/* Планшет: сітки стискаються раніше, ніж ламається шапка. */
@media (max-width: 1100px) {
	.cols { grid-template-columns: 1fr; }
	.board { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
	:root { --sidebar-w: 264px; --control-h: 40px; }

	main { padding: 12px; }

	.nav-toggle { display: inline-flex; }

	/* Меню — висувна шухляда поверх контенту. Стан тримає чекбокс усередині
	   .nav-toggle, ловить :has(); тому воно працює без JS. */
	.sidebar {
		position: fixed;
		inset: 0 auto 0 0;
		height: 100dvh;
		z-index: 60;
		transform: translateX(-100%);
		transition: transform .2s var(--ease);
		box-shadow: var(--shadow-lg);
		will-change: transform;
	}

	.nav-scrim {
		display: block;
		position: fixed;
		inset: 0;
		z-index: 50;
		background: var(--backdrop);
		opacity: 0;
		pointer-events: none;
		transition: opacity .2s var(--ease);
	}

	.shell:has(.nav-toggle input:checked) .sidebar { transform: none; }
	.shell:has(.nav-toggle input:checked) .nav-scrim { opacity: 1; pointer-events: auto; }

	.search-trigger kbd { display: none; }
	.timer .sub { display: none; }
	.timer-label { display: none; }

	/* Фільтрів буває вісім, а в один стовпчик це 700px до першого рядка даних.
	   Дві колонки: підписи короткі, а «Будь-який» у select читається і на 180px.
	   ponytail: згортати їх у <details> — це або ставка на те, що
	   `::details-content` дасть себе перекрити, або чекбокс і :has() у дванадцяти
	   файлах; дві колонки дають той самий виграш одним медіазапитом. */
	.filters > label, .filters > label.span-2, .filters > label.grow { flex: 1 1 calc(50% - 6px); }
	.filters > label.wide, .filter-actions { flex: 1 1 100%; }
	.filter-actions { margin-left: 0; }

	.page-head h1 { font-size: 20px; }
	.page-actions { width: 100%; margin-left: 0; }

	/* Вкладки прокручуються вбік, а не переносяться в три ряди. */
	.tabs {
		flex-wrap: nowrap;
		overflow-x: auto;
		scrollbar-width: none;
		overscroll-behavior-x: contain;
	}
	.tabs::-webkit-scrollbar { display: none; }
	.tabs a { flex: none; }

	/* На вузькому екрані стискати вже нема куди: «Коваленко Андрій Петрович» у
	   три рядки гірший за скрол. Тому тут таблиця повертається до природної
	   ширини — липка перша колонка лишається на місці й тримає рядок упізнаваним. */
	.table-wrap table { max-width: none; }

	/* Чотири колонки канбану і сім колонок місяця в портрет не влазять —
	   обидва скролять убік, а не тиснуть кожну колонку до слова в рядок. */
	.board { overflow-x: auto; grid-auto-flow: column; grid-auto-columns: 78vw; grid-template-columns: none; padding-bottom: 4px; }
	.cal { min-width: 680px; }
	.cal-week .cal-day { min-height: 200px; }
}

@media (max-width: 560px) {
	.grid-form { grid-template-columns: 1fr; }
	/* В одну колонку `span 2` створив би другу, неявну — і поле поїхало б за край. */
	.grid-form .span-2 { grid-column: auto; }
	.filters > label, .filters > label.span-2, .filters > label.grow { flex: 1 1 100%; }
	.filter-actions, .form-actions { flex-wrap: wrap; }
	.filter-actions > *, .form-actions > * { flex: 1 1 auto; }
	.totals > .total { min-width: 0; max-width: none; width: 100%; }
	.facts, .facts.pairs > div { grid-template-columns: 1fr; gap: 2px 0; }
	.facts dd { margin-bottom: 8px; }
	/* Рівно 2×2: `auto-fit` клав чотири плитки як 3 + 1 сироту. */
	.tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.board { grid-auto-columns: 86vw; }
	.page-actions .quiet, .page-actions a.btn, .page-actions button { flex: 1 1 auto; }
}
