/* То, чего в Bootstrap нет: полоса навигации, двухколоночный каркас страницы, сетка
   контролов панели, двойной ползунок и сетка слов. Всё остальное — кнопки, поля,
   спиннер, баннер — bootstrap-классы прямо в шаблонах компонентов.
   Полоса навигации общая на обе страницы и лежит здесь потому, что здесь же каркас,
   а файл подключается из base.html, то есть везде.
   Файл подключается после bootstrap.min.css, поэтому переопределения работают
   без !important и без раздувания селекторов.

   Клавиатура — keyboard.css, она же владеет масштабом --key-unit. Медиазапрос здесь
   ровно один — 975 px, на котором две колонки страницы схлопываются в одну; порог
   считается из ширины клавиатуры (см. комментарий у запроса), поэтому менять его
   в отрыве от масштабов в keyboard.css (1167/1071/640) нельзя. Панель порогов не имеет
   вовсе: её блоки ломаются по своей ширине через auto-fit — ширину им задаёт клавиатура
   над ними, а не окно, и связывать их с вьюпортом значило бы гадать. */

/* Полоса навигации и приложение справа от неё (dashboard.html). Flex, а не grid:
   колонок ровно две, вторая забирает остаток — раскладывать нечего.
   Полоса прижата к верху (align-items), потому что растянутый на всю высоту
   контейнера sticky-элемент не липнет: ему некуда съезжать */
.dashboard {
	display: flex;
	align-items: flex-start;
}

/* Ширина — под иконку с полями, подписей на полосе нет (они в title). Высота своя,
   в экран, и position: sticky: ниже 975 px .page теряет фиксированную высоту
   и страница прокручивается целиком, а разделы должны оставаться на виду */
.dash-nav {
	position: sticky;
	top: 0;
	flex: none;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.25rem;
	width: 3.5rem;
	height: 100vh;
	padding: 0.75rem 0;
	background: var(--bs-dark);
}

/* min-width обязателен: внутри .page треки minmax(22rem, 1fr), и без него флексу
   запрещает ужиматься автоминимум по содержимому */
.dashboard .page {
	flex: 1 1 auto;
	min-width: 0;
}

.dash-nav-link {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2.5rem;
	height: 2.5rem;
	border-radius: 0.5rem;
	color: rgba(255, 255, 255, 0.55);
	text-decoration: none;
}

.dash-nav-link:hover,
.dash-nav-link:focus-visible {
	color: #fff;
	background: rgba(255, 255, 255, 0.1);
}

/* Текущий раздел — заливкой, а не одним цветом иконки: подписей на полосе нет,
   и различать активный пункт по оттенку серого пришлось бы вглядываясь */
.dash-nav-link.active {
	color: #fff;
	background: rgba(255, 255, 255, 0.2);
}

/* Каркас — grid, а не flex: панель стоит под клавиатурой, а список слов остаётся
   во всю высоту справа — flex-обёрткам для этого понадобился бы лишний div.
   Ширину левой колонки задаёт клавиатура: 15u — её собственная ширина (keyboard.css),
   поэтому и панель под ней не может вылезти за её край без подгонки пикселей */
.page {
	display: grid;
	grid-template-columns: calc(var(--key-unit) * 15) minmax(22rem, 1fr);
	grid-template-rows: auto 1fr;
	grid-template-areas:
		"keys  words"
		"panel words";
	gap: 1rem;
	height: 100vh;
	padding: 1.5rem 1rem;
}

.pane-keys {
	grid-area: keys;
	background: #fff;
	padding: 15px;
	border-radius: 15px;
}

/* Своей ширины у панели нет: её задаёт клавиатура над ней. min-height нужен, чтобы
   на низком окне содержимое прокручивалось внутри панели (она стоит в ряду 1fr),
   а не выдавливало каркас */
.pane-panel {
	grid-area: panel;
	min-height: 0;
	overflow-y: auto;
	background: #fff;
	padding: 15px;
	border-radius: 15px;
}

/* Панель — четыре блока в столбик: из чего набираем (алфавит), какие слова годятся
   (фильтрация), в каких границах — длина и частотность (ограничения) — и запуск.
   Одной общей сетки на четыре колонки больше нет: у контролов внутри разная
   минимальная ширина, и общая сетка резала каждый по чужой мерке — колонки
   теперь дело самого блока.
   align-content обязателен: панель стоит в ряду 1fr и выше своего содержимого,
   а умолчание grid'а — stretch, и лишнюю высоту он раздаёт рядам, растаскивая блоки
   по всей панели */
.panel-grid {
	display: grid;
	gap: 1rem;
	align-content: start;
}

/* Алфавит отделён от остального чертой: он про клавиатуру (что выделено и что из этого
   годится), а всё ниже — про слова */
.panel-alphabet {
	border-bottom: 1px dashed #ccc;
	padding-bottom: 1rem;
}

/* Колонки внутри блока — auto-fit, а не фиксированное число, и медиазапросов у панели
   поэтому нет вовсе: блок ломается по своей ширине, а её задаёт клавиатура (15u),
   а не ширина окна. Пустые треки auto-fit схлопывает, поэтому колонок ровно столько,
   сколько контролов встало в ряд. Минимум разный: подписи радиокнопок («Только эти
   символы», «Имена собственные») укладываются в строку от 9.5rem, а ползункам
   нужно заметно больше: под ползунком частотности стоит ещё и ряд кнопок-порогов,
   и в 12rem он встаёт только целиком */
.panel-filters,
.panel-limits {
	display: grid;
	gap: 1rem;
	align-items: start;
}

.panel-filters {
	grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
}

.panel-limits {
	grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
}

/* Кнопки у правого края: они завершают панель, а не продолжают список параметров,
   и по левому краю читались бы ещё двумя из них. Зазор — тот же 0.5rem, которым
   Bootstrap (gap-2) разводит кнопки в шапке клавиатуры: слипшиеся кнопки читаются
   как одна группа переключателей */
.panel-actions {
	display: flex;
	flex-wrap: wrap;
	justify-content: flex-end;
	gap: 0.5rem;
}

/* Меню порций (PreviewButton) позиционируется здесь: у Bootstrap этим занят Popper
   из JS-сборки, которой в проекте нет, и .dropdown-menu остаётся position: absolute
   без координат. Вверх — потому что панель прокручивается внутри себя (.pane-panel,
   overflow-y: auto), и выпавшее вниз меню она обрежет; от правого края — потому что
   кнопки к нему прижаты, и влево меню растёт в панель, а не за её край */
.panel-actions .dropdown-menu {
	top: auto;
	bottom: 100%;
	left: auto;
	right: 0;
	margin-bottom: 0.125rem;
}

/* Прокручивается только список слов, а не страница: min-height нужен, чтобы
   грид-элемент дал сетке внутри себя сжаться (иначе поедет весь каркас) */
.pane-words {
	grid-area: words;
	min-width: 0;
	min-height: 0;
	background: #fff;
	padding: 15px;
	border-radius: 20px;
}

/* Колонки резиновые: сколько влезет по 7rem, но не больше семи — восьмая читается
   уже сплошной плотной сеткой. Потолок задан нижней границей трека, а не max-width'ом
   у сетки: тот оставил бы пустоту справа, а так лишнюю ширину делят между собой
   те же семь колонок. 6rem в формуле — это шесть зазоров между семью колонками,
   то есть column-gap строкой ниже: менять их порознь нельзя.
   Высота ряда задана явно, а не выведена
   из содержимого: у слова ниже стоит overflow: hidden (ради многоточия), а он обнуляет
   автоминимум грид-элемента — и грид вместо прокрутки ужимает ряды под высоту колонки,
   накладывая строки друг на друга. Слово всегда в одну строку, поэтому ряд равен ей */
.words {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(max(7rem, (100% - 6rem) / 7), 1fr));
	grid-auto-rows: 1.5rem;
	gap: 0 1rem;
	align-content: start;
	flex: 1;
	min-height: 0;
	overflow-y: auto;
	border-top: 1px solid #333;
	border-bottom: 1px solid #333;
}

/* Заглушка вместо списка (ещё не искали / ничего не нашлось). Занимает всё свободное
   место колонки и центрирует строку в нём: строка в верхнем углу пустой области
   читается как обрезанный результат. На узком экране колонка сжата по содержимому,
   и центрировать там нечего — flex просто отдаёт строке её высоту */
.words-empty {
	flex: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	margin: 0;
	text-align: center;
}

/* Ряд сетки — слово и (в режиме подсветки) метка с числом пальцев. Flex, а не просто
   строка: многоточие должно съедать слово, а не метку, — за это отвечает min-width: 0
   на слове и запрет сжатия на метке */
.words > div {
	display: flex;
	align-items: baseline;
	gap: 0.35rem;
}

.words .word {
	min-width: 0;
	/* overflow: hidden; */
	/* text-overflow: ellipsis; */
	white-space: nowrap;
	letter-spacing: 1px;
}

/* Раскрашенное слово: letter-spacing тут не даёт зазора — он входит в ширину буквы
   и красится вместе с ней, поэтому фоны сходятся встык и границы пальцев не видно.
   Тот же 1px отдан margin'у: суммарная ширина слова прежняя, но зазор виден */
.words .word-colored {
	/* letter-spacing: 0; */
}

.words .word-colored span {
	/* margin-right: 1px; */
}

/* Метка мельче слова и вторичного цвета (text-body-secondary в шаблоне): она подпись
   к слову, а не второе значение в ряду. Не кружок: в метке разбивка по рукам («1 + 2»),
   а формула в 18px круг не влезает и переносить её нельзя — отсюда padding вместо
   фиксированных width/height и nowrap */
.words .word-fingers {
	flex: none;
	letter-spacing: 0;
	border-radius: .5rem;
	padding: 0 .35rem;
	white-space: nowrap;
	display: inline-flex;
	justify-content: center;
	font-size: 12px;
	background: #f8f8f8;
	line-height: 1;
	align-items: center;
}

/* Двойной ползунок: два input[type=range] друг на друге. Класс про механизм,
   а не про длину — ограничений на панели два (длина слова и полоса частотности),
   и рисует их обоих один DualRange.
   Дорожку рисует нижний, у верхнего она прозрачна; указатель ловят только бегунки,
   иначе верхний ползунок перехватывал бы клики по всей дорожке.
   Псевдоэлементы бегунка не объединяются в один селектор: браузер отбрасывает
   всё правило целиком, встретив незнакомый ему префикс. */

.dualrange {
	position: relative;
	height: 1.5rem;
}

.dualrange input {
	position: absolute;
	inset: 0;
	width: 100%;
	margin: 0;
	pointer-events: none;
}

/* Кто наверху, решает компонент, а не порядок в разметке: у слипшихся бегунков
   иначе получается тупик — верхний перекрывает нижний, а двигать можно только нижний */
.dualrange input.top {
	z-index: 2;
}

.dualrange input.top::-webkit-slider-runnable-track {
	background: transparent;
}

.dualrange input.top::-moz-range-track {
	background: transparent;
}

.dualrange input::-webkit-slider-thumb {
	pointer-events: auto;
}

.dualrange input::-moz-range-thumb {
	pointer-events: auto;
}

.alert-dismissible .btn-close {
	padding: 0.75rem;
}

/* Одна колонка. Фиксированная высота снимается: на телефоне она вредна — адресная
   строка сама меняет вьюпорт, — и страница прокручивается обычным образом,
   а сетка слов своей прокрутки не имеет. Порог считается, а не подбирается:
   две колонки — это 15u + 1rem + 22rem + 2rem, при --key-unit 2.4rem ровно 61rem = 976px */
@media (max-width: 975px) {
	.page {
		grid-template-columns: minmax(0, 1fr);
		grid-template-rows: none;
		grid-template-areas:
			"keys"
			"panel"
			"words";
		height: auto;
		min-height: 100vh;
	}

	.pane-panel {
		overflow-y: visible;
	}

	.words {
		overflow: visible;
	}
}
