/* =============================================================================
   Панель управления LINK-UP-ISP
   Раскладка списков перенесена из старого биллинга, оформление новое.
   Цвета сняты с логотипа: зелёный #27672F, тёмно-серый #424243.
   ============================================================================= */

:root {
	/* Фирменный зелёный из логотипа: кнопки, активные пункты, фокус */
	--brand:        #27672F;
	--brand-dark:   #1D4F24;
	--brand-soft:   #EDF4EE;
	--brand-line:   #C9DECD;

	/* Ссылки — бирюзовый: заметно другой тон, не путается со статусом */
	--link:         #0F766E;
	--link-hover:   #0B5B55;

	--text:         #424243;
	--text-strong:  #2B2B2C;
	--muted:        #7A8079;
	--bg:           #F4F7F4;
	--card:         #FFFFFF;
	--border:       #DDE5DD;
	--border-soft:  #EAF0EA;

	/* Сигнальные. Яркий зелёный больше нигде не используется — поэтому
	   в таблице он и притягивает взгляд */
	--up:           #16A34A;
	--down:         #DC2626;
	--warn:         #EA580C;

	--radius:       8px;
	--radius-sm:    6px;
}

/* --- База ----------------------------------------------------------------- */

body {
	padding-top: 0;
	background-color: var(--bg);
	color: var(--text);
	font-size: 14px;
}

a {
	color: var(--link);
	text-decoration: none;
}

a:hover,
a:focus {
	color: var(--link-hover);
	text-decoration: underline;
}

.app-icon {
	width: 14px;
	height: 14px;
	fill: currentColor;
	vertical-align: -2px;
}

/* --- Шапка ---------------------------------------------------------------- */

.app-navbar {
	padding: 0 0;
	background-color: var(--card);
	border-bottom: 1px solid var(--border);
	box-shadow: 0 1px 2px rgba(39, 103, 47, 0.05);
}

.app-navbar .navbar-brand {
	padding: 6px 0;
	margin-right: 28px;
}

.app-navbar .navbar-brand img {
	display: block;
	height: 32px;
	width: auto;
}

.app-navbar .nav-link {
	padding: 8px 12px;
	color: var(--text);
	font-weight: 500;
	border-radius: var(--radius-sm);
}

.app-navbar .nav-link:hover,
.app-navbar .nav-link:focus {
	color: var(--brand);
	background-color: var(--brand-soft);
	text-decoration: none;
}

.app-navbar .dropdown-menu {
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	box-shadow: 0 6px 18px rgba(39, 103, 47, 0.10);
	font-size: 14px;
}

.app-navbar .dropdown-item:active,
.app-navbar .dropdown-item:focus,
.app-navbar .dropdown-item:hover {
	color: var(--brand);
	background-color: var(--brand-soft);
}

.app-navbar-user .nav-link {
	color: var(--muted);
}

.app-user-name {
	color: var(--muted);
	font-size: 12px;
}

/* --- Тело страницы -------------------------------------------------------- */

.app-body {
	padding: 12px 16px 0;
}

/* Строка с названием раздела: одна тонкая полоса, как в старом биллинге */
.app-head {
	display: flex;
	align-items: center;
	margin-bottom: 10px;
	padding: 6px 12px;
	background-color: var(--card);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	font-size: 13px;
}

.app-head-title {
	flex: 1 1 auto;
	color: var(--text-strong);
	font-weight: 600;
}

.app-head .btn {
	padding: 2px 10px;
	font-size: 12px;
}

/* Время генерации страницы внизу */
.page-time {
	margin: 10px 0 6px;
	color: var(--muted);
	font-size: 11px;
	text-align: center;
}

/* --- Кнопки и поля -------------------------------------------------------- */

.btn {
	border-radius: var(--radius-sm);
}

.btn-primary {
	background-color: var(--brand);
	border-color: var(--brand);
}

.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active,
.btn-primary:first-child:active {
	background-color: var(--brand-dark);
	border-color: var(--brand-dark);
}

.btn-check:focus + .btn-primary,
.btn-primary:focus {
	box-shadow: 0 0 0 0.2rem rgba(39, 103, 47, 0.25);
}

.btn-outline-secondary {
	color: var(--text);
	border-color: var(--border);
	background-color: var(--card);
}

.btn-outline-secondary:hover,
.btn-outline-secondary:focus,
.btn-outline-secondary:active {
	color: var(--brand);
	border-color: var(--brand-line);
	background-color: var(--brand-soft);
}

.form-control,
.form-select {
	border-color: var(--border);
	border-radius: var(--radius-sm);
	color: var(--text);
	font-size: 14px;
}

.form-control:focus,
.form-select:focus {
	border-color: var(--brand-line);
	box-shadow: 0 0 0 0.2rem rgba(39, 103, 47, 0.15);
}

.form-check-input:checked {
	background-color: var(--brand);
	border-color: var(--brand);
}

/* --- Таблицы -------------------------------------------------------------- */

.list-main .table {
	margin-bottom: 0;
	background-color: var(--card);
	border-color: var(--border-soft);
	font-size: 14px;
}

.list-main .table > thead > tr > th {
	background-color: var(--brand-soft);
	border-bottom: 1px solid var(--brand-line);
	color: var(--text-strong);
	font-weight: 600;
	white-space: nowrap;
}

.list-main .table > tbody > tr > td {
	border-color: var(--border-soft);
}

.list-main .table-striped > tbody > tr:nth-of-type(odd) > td {
	--bs-table-accent-bg: transparent;
	background-color: #FAFCFA;
}

.list-main .table-hover > tbody > tr:hover > td {
	--bs-table-accent-bg: transparent;
	background-color: var(--brand-soft);
}

.list-empty {
	padding: 24px 12px;
	color: var(--muted);
	text-align: center;
}

/* --- Значения портов ------------------------------------------------------ */

.port-up,
.speed-1000 {
	color: var(--up);
	font-weight: 600;
}

.port-down,
.speed-10 {
	color: var(--down);
	font-weight: 600;
}

.speed-100 {
	color: var(--warn);
	font-weight: 600;
}

.port-none {
	color: var(--muted);
}

.port-num {
	font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
	font-variant-numeric: tabular-nums;
	font-weight: 600;
}

.port-arrow-up {
	color: var(--warn);
}

.port-arrow-down {
	color: var(--up);
}

.wave-1310 {
	color: #1F6FEB;
}

.wave-1550 {
	color: #C2620B;
}

.ddm {
	font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
	font-variant-numeric: tabular-nums;
}

.ddm-danger {
	color: var(--down);
}

.ddm-warn {
	color: var(--warn);
}

.mono {
	font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
	font-variant-numeric: tabular-nums;
}

/* Метка типа устройства */
.dev-type {
	display: inline-block;
	padding: 0 5px;
	border: 1px solid currentColor;
	border-radius: 4px;
	font-size: 11px;
	font-weight: 600;
	line-height: 16px;
	vertical-align: middle;
	white-space: nowrap;
}

.dev-type-sw {
	color: var(--muted);
}

.dev-type-olt {
	color: #7C3AED;
}

.session-up {
	color: var(--up);
}

.session-down {
	color: var(--down);
}

.free-port {
	color: var(--muted);
	font-style: italic;
}

/* --- Стартовая страница --------------------------------------------------- */

.start-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
	gap: 14px;
}

.start-card {
	display: block;
	padding: 18px;
	background-color: var(--card);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	color: var(--text);
	transition: border-color .15s, box-shadow .15s;
}

.start-card:hover {
	border-color: var(--brand-line);
	box-shadow: 0 4px 14px rgba(39, 103, 47, 0.10);
	color: var(--text);
	text-decoration: none;
}

.start-card-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 38px;
	height: 38px;
	margin-bottom: 10px;
	border-radius: var(--radius-sm);
	background-color: var(--brand-soft);
	color: var(--brand);
}

.start-card-icon svg {
	width: 18px;
	height: 18px;
	fill: currentColor;
}

.start-card-title {
	display: block;
	margin-bottom: 4px;
	color: var(--text-strong);
	font-size: 15px;
	font-weight: 600;
}

.start-card-text {
	display: block;
	color: var(--muted);
	font-size: 13px;
	line-height: 1.4;
}

/* --- Вход ----------------------------------------------------------------- */

/* Мягкий зелёно-жёлтый переход с официального сайта. В рабочих экранах его нет:
   там он мешал бы читать таблицы */
.login-page {
	min-height: 100vh;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 24px;
	background: linear-gradient(135deg, #F5F7C8 0%, #DCEFCB 45%, #C7E9D6 100%);
}

.login-box {
	width: 100%;
	max-width: 380px;
}

.login-logo {
	margin-bottom: 18px;
	text-align: center;
}

.login-logo img {
	height: 44px;
	width: auto;
}

.login-card {
	padding: 24px;
	background-color: var(--card);
	border-radius: 14px;
	box-shadow: 0 10px 30px rgba(31, 79, 36, 0.12);
}

.login-title {
	margin-bottom: 18px;
	color: var(--text-strong);
	font-size: 16px;
	font-weight: 600;
	text-align: center;
}

.login-field {
	margin-bottom: 14px;
}

.login-field label {
	display: block;
	margin-bottom: 4px;
	color: var(--muted);
	font-size: 12px;
	font-weight: 600;
}

/* --- Страница ошибки ------------------------------------------------------ */

.page-error {
	min-height: 100vh;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 24px;
	background-color: var(--bg);
}

.page-error-box {
	max-width: 560px;
	padding: 24px;
	background-color: var(--card);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	text-align: center;
}

.page-error-title {
	margin-bottom: 8px;
	color: var(--down);
	font-size: 18px;
	font-weight: 600;
}

.page-error-text {
	color: var(--text);
	line-height: 1.5;
}

/* =============================================================================
   Ниже — раскладка списков, перенесённая из старого биллинга:
   колонка отбора, подвал, пагинация, копирование значений, окно сообщений.
   Классы и структура сохранены — на них завязан main.js.
   ============================================================================= */

.management-menu {
	position: relative;
	display: inline-block;
}
.management-menu-link {
	cursor: pointer;
	-webkit-user-select: none; /* для Safari и старых версий Chrome */
	-moz-user-select: none;
	-ms-user-select: none;
	user-select: none;
}
.management-menu-content {
	display: none;
	position: absolute;
	background-color: #f9f9f9;
	min-width: 175px;
	box-shadow: 0px 0px 1px 1px #ddd;
	z-index: 1;
	right: 0;
	left: 50%;
	transform: translateX(-50%);
}
.management-menu-content a {
	color: black;
	padding: 10px;
	text-decoration: none;
	display: block;
}
.management-menu-content a:hover {
	background-color: #efefef;
}
.management-menu:hover .management-menu-content {
	display: block;
}
/* Стрелка направления сортировки в шапке таблицы. Рисуется целиком стилями: в шаблонах
   разметки значка нет, класс проставляет TableView() той колонке, по которой список
   отсортирован сейчас */
.table-sort-asc:after,
.table-sort-desc:after {
	font-family: 'Glyphicons Halflings';
	font-style: normal;
	font-weight: 400;
	font-size: 11px;
	line-height: 1;
	padding-left: 5px;
	moz-osx-font-smoothing: grayscale;
	webkit-font-smoothing: antialiased;
}
.table-sort-asc:after {
	content: "\e093";
}
.table-sort-desc:after {
	content: "\e094";
}
/* Ячейка с копированием значения: значок стоит сразу за значением и виден при наведении.
   Только на ПК — на телефоне наведения нет, а место в ячейке дороже.
   Значок скрывается видимостью, а не display: он остаётся в потоке и держит своё место,
   поэтому колонка не дёргается по ширине под курсором */
/* Значение и значок копирования — одной строкой. Без запрета переноса значок при узкой
   колонке спрыгивает под значение, строка становится выше, и содержимое соседних колонок
   разъезжается по высоте */
.list-copy {
	position: relative;
	white-space: nowrap;
}
/* Размер задан жёстко и выравнивание по середине: у шрифта значков свои метрики, и кнопка,
   оставленная «как есть», растягивала строку — текст в этой ячейке вставал не на одну высоту
   с соседними колонками */
.list-copy-btn {
	visibility: hidden;
	box-sizing: border-box;
	display: inline-block;
	width: 16px;
	height: 14px;
	margin-left: 5px;
	padding: 0;
	border: 0;
	background: transparent;
	color: #aaaaaa;
	font-size: 0;
	line-height: 14px;
	text-align: center;
	vertical-align: middle;
	overflow: hidden;
}
.list-copy-btn:hover {
	color: var(--link);
}
.list-copy-btn svg {
	width: 12px;
	height: 12px;
	fill: currentColor;
}
/* «Скопировано» рядом с самой ячейкой: короткая подсказка вместо большого уведомления
   через весь экран — действие мелкое и происходит часто */
.list-copy-note {
	position: absolute;
	right: 2px;
	top: -20px;
	z-index: 5;
	padding: 2px 7px;
	border-radius: 3px;
	background-color: rgba(51, 51, 51, 0.92);
	color: #ffffff;
	font-size: 11px;
	line-height: 15px;
	white-space: nowrap;
	pointer-events: none;
}
@media (min-width: 992px) {
	.list-copy:hover .list-copy-btn {
		visibility: visible;
	}
}
/* На телефоне кнопки нет вовсе: наведения там не бывает, а место в ячейке дорого.
   Именно display: none — так она не занимает места, в отличие от скрытой видимостью */
@media (max-width: 991px) {
	.list-copy-btn {
		display: none;
	}
}
/* Значения в строке выравниваются по середине. У bootstrap ячейки прижаты к верху, и когда
   одна колонка переносится на две строки (адрес, название пакета на узком экране), короткие
   значения соседних колонок повисают у верхнего края — строка выглядит рваной */
.list-main .table > tbody > tr > td {
	vertical-align: middle;
}
/* Список ошибок описания внутри одной плашки: плотнее обычного, это сообщение разработчику */
.list-error {
	margin: 4px 0 0;
	padding-left: 20px;
}
.list-error li {
	margin-top: 2px;
}
/* Число активных условий отбора на кнопке «Фильтры»: колонку отбора можно свернуть,
   и тогда о действующем отборе больше ничто не напоминает.
   Синий кружок убран 2026-08-29 — на светлой кнопке в строке с названием он выглядел
   наклейкой из другого интерфейса. Теперь это просто число рядом с подписью, отделённое
   тонкой чертой, а о том, что отбор задан, говорит сама кнопка: рамка и текст темнее */
.panel-toggle-count {
	margin-left: 7px;
	padding-left: 7px;
	border-left: 1px solid #dddddd;
	color: #767676;
	font-weight: 600;
}
/* ------------------------------------------------------------------------- */
/* Раскладка списка: слева колонка поиска и отбора, справа таблица во всю ширину */
.list-layout {
	display: flex;
	align-items: flex-start;
	margin: 0;
}
/* Прямые углы — решение заказчика от 2026-08-16, как и у строки с названием модуля */
.list-side {
	flex: 0 0 250px;
	width: 250px;
	margin-right: 18px;
	padding: 14px 14px 10px;
	border: 1px solid #e2e2e2;
	border-radius: 0;
	background-color: #fafafa;
}
/* Правая часть обязана уметь сжиматься, иначе широкая таблица растянет страницу */
.list-main {
	flex: 1 1 auto;
	min-width: 0;
}
.list-side-title {
	margin-bottom: 8px;
	padding-bottom: 6px;
	border-bottom: 1px solid #e6e6e6;
	color: #333333;
	font-weight: 600;
}
.list-side-title + .list-side-item {
	margin-top: 0;
}
.list-side-item {
	margin-bottom: 10px;
}
/* Уведомления toastr. Вендорный toastr.min.css в проекте НЕПОЛНЫЙ: в нём есть стили заголовка,
   текста и крестика, но нет ни позиционирования контейнера, ни фона по типам сообщения.
   Из-за этого уведомления выходили прозрачными, белым по белому, и лезли под верхнее меню —
   то есть showSuccess() и showError() не было видно нигде в панели. Дописываем недостающее
   здесь: вендорный файл не правим, его правки потеряются при обновлении библиотеки */
#toast-container {
	position: fixed;
	top: 62px;
	right: 16px;
	z-index: 1200;
	width: 320px;
	max-width: calc(100% - 32px);
}
#toast-container > div {
	margin-bottom: 8px;
	padding: 12px 14px;
	background-color: #333333;
	box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25);
	color: #ffffff;
	font-size: 14px;
	line-height: 1.4;
	opacity: 1;
	cursor: pointer;
}
#toast-container > .toast-success {
	background-color: #46874a;
}
#toast-container > .toast-error {
	background-color: #b0413e;
}
#toast-container > .toast-warning {
	background-color: #bf8100;
}
#toast-container > .toast-info {
	background-color: #31708f;
}
/* Диалог поверх страницы: сообщение, которое нельзя не заметить. Своя разметка, потому что
   в bootstrap.min.css этого проекта стилей модального окна нет — вырезаны вместе с адаптивной
   частью. Закрывается кнопкой, крестиком, Esc и щелчком по затемнению */
.app-dialog-back {
	position: fixed;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	z-index: 1100;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 16px;
	background-color: rgba(0, 0, 0, 0.45);
}
.app-dialog {
	width: 100%;
	max-width: 460px;
	background-color: #ffffff;
	border: 1px solid #d0d0d0;
	box-shadow: 0 12px 32px rgba(0, 0, 0, 0.25);
}
.app-dialog-head {
	display: flex;
	align-items: center;
	padding: 12px 14px;
	border-bottom: 1px solid #ececec;
}
.app-dialog-icon {
	flex: 0 0 auto;
	margin-right: 10px;
	color: var(--warn);
	line-height: 0;
}
.app-dialog-icon svg {
	width: 16px;
	height: 16px;
	fill: currentColor;
}
.app-dialog-title {
	flex: 1 1 auto;
	color: #333333;
	font-size: 15px;
	font-weight: 600;
}
.app-dialog-close {
	flex: 0 0 auto;
	width: 28px;
	height: 28px;
	padding: 0;
	border: 0;
	background: transparent;
	color: #999999;
	font-size: 20px;
	line-height: 26px;
}
.app-dialog-close:hover {
	color: #333333;
}
.app-dialog-body {
	padding: 14px;
	color: #333333;
	font-size: 14px;
	line-height: 1.45;
}
.app-dialog-body ul {
	margin: 0;
	padding-left: 18px;
}
.app-dialog-body li + li {
	margin-top: 6px;
}
.app-dialog-foot {
	padding: 12px 14px;
	border-top: 1px solid #ececec;
	text-align: right;
}
/* Звёздочка у обязательного фильтра */
.list-side-required {
	margin-left: 3px;
	color: var(--down);
	font-weight: bold;
}
.list-side-item label {
	display: block;
	margin-bottom: 3px;
	color: #666666;
	font-size: 12px;
	font-weight: 600;
}
.list-side-item .form-control {
	width: 100%;
	height: 32px;
	padding: 4px 8px;
}
/* Крестик очистки внутри строки поиска: показывается скриптом, только когда есть что стирать */
.list-clear-box {
	position: relative;
	display: block;
}
.list-clear-box .form-control {
	padding-right: 26px;
}
/* В многострочном поле крестик вынесен на строку подписи, к правому краю поля: внутри он
   налезал бы на полосу прокрутки сверху и на уголок изменения размера снизу */
.list-clear-box textarea + .list-clear {
	top: -21px;
	right: 0;
	height: 20px;
	line-height: 18px;
	padding-right: 2px;
	text-align: right;
}
/* Место справа под крестик тут не нужно — он вне поля */
.list-clear-box textarea.form-control {
	padding-right: 8px;
}
.list-clear {
	position: absolute;
	top: 0;
	right: 0;
	display: none;
	width: 24px;
	height: 32px;
	padding: 0;
	border: 0;
	background: transparent;
	color: #c8c8c8;
	font-size: 17px;
	line-height: 30px;
}
.list-clear:hover {
	color: #777777;
}
.list-side-check {
	display: block;
	margin: 0;
	color: #444444;
	font-size: 13px;
	font-weight: normal;
	cursor: pointer;
}
.list-side-check input {
	margin-right: 6px;
}
/* Даты — двумя строками на всю ширину колонки: дата вводится руками в поле,
   либо выбирается в календаре по кнопке справа. Само поле type="date" скрыто —
   оно нужно только чтобы показать календарь браузера */
.list-side-date {
	display: flex;
	align-items: center;
	margin-bottom: 6px;
}
.list-side-date:last-child {
	margin-bottom: 0;
}
/* В строке с календарём и в строке диапазона поле обёрнуто в .list-clear-box (крестик очистки),
   поэтому шириной управляет обёртка, а само поле занимает её целиком */
.list-side-date .list-clear-box,
.list-side-range .list-clear-box {
	flex: 1 1 auto;
	min-width: 0;
}
.list-side-date .list-side-date-text {
	width: 100%;
}
.list-side-date .list-side-date-btn {
	flex: 0 0 auto;
	height: 32px;
	margin-left: 6px;
	padding: 4px 10px;
}
.list-side-date-hidden {
	position: absolute;
	width: 0;
	height: 0;
	padding: 0;
	border: 0;
	opacity: 0;
}
/* Список значений, введённый руками: высоту можно тянуть, ширину — нет,
   иначе поле вылезет за колонку отбора */
.list-side-list {
	resize: vertical;
	min-height: 80px;
	font-size: 13px;
}
/* Числовой диапазон: поле и подпись единицы измерения справа от него */
.list-side-range {
	display: flex;
	align-items: center;
	margin-bottom: 6px;
}
.list-side-range:last-child {
	margin-bottom: 0;
}
/* Выравнивание по левому краю, а не по правому: подписи «от» и «до» — это placeholder,
   при выравнивании вправо они прижимались к резерву под крестик очистки и висели в пустоте */
.list-side-range .list-side-range-text {
	width: 100%;
}
.list-side-range .list-side-range-unit {
	flex: 0 0 auto;
	min-width: 26px;
	margin-left: 8px;
	color: #777777;
	font-size: 12px;
}
/* Полоса действий: две кнопки в одну строку, поровну по ширине. «Сбросить» стоит правее —
   стирающее действие не должно оказаться там, куда палец идёт по привычке. Класс btn-block
   в шаблоне остаётся, его ширину и отступы перекрывают правила ниже */
.list-side-buttons {
	display: flex;
	margin-top: 14px;
	padding-top: 12px;
	border-top: 1px solid #e6e6e6;
}
.list-side-buttons .btn {
	flex: 1 1 0;
	width: auto;
	margin-top: 0;
	margin-bottom: 0;
}
.list-side-buttons .btn + .btn {
	margin-left: 8px;
}
/* Кнопки не уезжают вверх при прокрутке колонки отбора. Только на ПК: там колонка
   прокручивается сама (высоту ей задаёт tableFit()), а на телефоне прокручивается страница
   целиком, и вторая прилипшая полоса рядом с подвалом только мешала бы.
   Свой фон обязателен — иначе поля просвечивают под кнопками при прокрутке */
@media (min-width: 992px) {
	/* Нижний отступ колонки отдаём самой полосе кнопок: иначе под ней остаётся щель,
	   в которую при прокрутке проглядывает верх следующего поля */
	.list-side {
		padding-bottom: 0;
	}
	.list-side-buttons {
		position: sticky;
		bottom: 0;
		z-index: 1;
		padding-bottom: 12px;
		background-color: #fafafa;
	}
}
/* Переключатель колонки отбора живёт в горизонтальном меню: своего места в раскладке
   страницы он не занимает. Скриптом показывается только на страницах со списком */
/* Селектор с двумя классами: у bootstrap правило .nav > li специфичнее одиночного класса */
.navbar-nav > .panel-toggle {
	display: none;
}
/* После нажатия ссылка остаётся в фокусе, а браузер и bootstrap рисуют вокруг неё рамку
   и подложку — для этой кнопки они не нужны */
.navbar-nav > .panel-toggle > a:focus,
.navbar-nav > .panel-toggle > a:active {
	outline: none;
	background-color: transparent;
}
/* Кнопка «Фильтры» после переноса скриптом в строку с названием модуля. Прижата к правому
   краю флотом, а не порядком в разметке: в саму строку она попадает второй, после названия.
   Разделитель «/», который bootstrap рисует между пунктами (.breadcrumb > li + li:before),
   здесь не нужен — это не следующий шаг пути, а кнопка */
.app-head .panel-toggle {
	float: right;
	list-style: none;
	/* Кнопка выше строки текста (22px против 18,56), поэтому по вертикали её центрирует
	   этот отступ: без него сверху остаётся 5px, а снизу полтора */
	margin-top: -2px;
}
.app-head .panel-toggle:before {
	content: "";
	padding: 0;
}
/* Настоящая кнопка, а не ссылка: та же светлая кнопка bootstrap, что «Сбросить» в колонке
   отбора, только ниже — строка с названием модуля тонкая. Классы .btn в разметку не ставим:
   тот же элемент лежит в меню, пока скрипт не перенёс его сюда.
   Значок и подпись центрируются флексом: у шрифта значков свои метрики, и по базовой линии
   значок садится выше середины (bootstrap для этого и держит у .glyphicon сдвиг top: 1px).
   box-sizing задан явно — глобального border-box в этой сборке bootstrap нет, и высота
   считалась бы вместе с отступами и рамкой */
.app-head .panel-toggle > a {
	display: inline-flex;
	align-items: center;
	box-sizing: border-box;
	height: 22px;
	padding: 0 10px;
	border: 1px solid #cccccc;
	border-radius: 4px;
	background-color: #ffffff;
	color: #333333;
	font-size: 12px;
	line-height: 1;
	text-decoration: none;
}
.app-head .panel-toggle a svg {
	width: 12px;
	margin-right: 5px;
	height: 12px;
	fill: currentColor;
}
.app-head .panel-toggle > a:hover,
.app-head .panel-toggle > a:focus {
	border-color: #adadad;
	background-color: #e6e6e6;
	color: #333333;
	text-decoration: none;
	outline: none;
}
/* Отбор задан: кнопка темнее, число рядом с подписью тоже. Класс ставит скрипт.
   Правило стоит ПОСЛЕ базового намеренно: специфичность у них одинаковая, и записанное
   выше просто не сработало бы */
.app-head .panel-toggle-active > a {
	border-color: #adadad;
	color: #111111;
}
.app-head .panel-toggle-active > a .panel-toggle-count {
	color: #111111;
}
.list-side-off .list-side {
	display: none;
}
/* Подвал правой части: переход по страницам слева, счётчик и «Записей» справа */
.list-foot {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	margin-top: 8px;
}
.list-pages {
	display: flex;
	align-items: center;
}
.list-pages .btn {
	width: 32px;
	margin-right: 4px;
	padding: 5px 0;
	text-align: center;
}
.list-pages .btn svg {
	width: 12px;
	height: 12px;
	fill: currentColor;
}
/* Недоступные кнопки перехода: видно, что дальше листать некуда */
.list-pages .btn.disabled {
	color: #bbbbbb;
	background-color: #f7f7f7;
}
.list-pages .list-pages-input[disabled] {
	background-color: #f7f7f7;
	color: #999999;
}
.list-pages-text {
	margin: 0 6px;
	color: #666666;
	white-space: nowrap;
}
.list-pages .list-pages-input {
	width: 56px;
	height: 30px;
	padding: 4px 6px;
	text-align: center;
}
/* После щелчка мышью кнопка остаётся в фокусе, и браузер рисует вокруг неё рамку — выглядит
   как «залипла нажатой». Убираем её только для мыши: :focus-visible срабатывает при переходе
   клавиатурой, там рамка нужна. Браузеры, которые :focus-visible не знают, оставят рамку —
   это не ошибка, а прежнее поведение */
.list-foot .btn:focus:not(:focus-visible),
.list-foot .btn:active:focus:not(:focus-visible) {
	outline: none;
}
/* Кнопки подвала: «Обновить», «Ссылка», «Выгрузить» — одинаковый отступ у всех трёх.
   position нужен для подсказки «Скопировано»: она крепится к самой кнопке */
.list-reload,
.list-link,
.list-export {
	position: relative;
	margin-left: 10px;
}
/* Подсказка у кнопки подвала встаёт над ней по центру, а не у правого края, как в ячейке */
.list-foot .list-copy-note {
	right: auto;
	left: 50%;
	top: -24px;
	transform: translateX(-50%);
}
.list-found {
	margin-left: auto;
	margin-right: 18px;
	color: #777777;
}
.list-records {
	display: flex;
	align-items: center;
}
.list-records label {
	margin-bottom: 0;
	margin-right: 8px;
	color: #666666;
	font-weight: 600;
	white-space: nowrap;
}
.list-records .form-control {
	width: 80px;
	height: 32px;
	padding: 4px 8px;
}
/* Стартовая высота блоков списка на ПК: чтобы страница не «собиралась на глазах».
   Точную высоту считает tableFit() в modal.js, но он выполняется после разбора страницы,
   а до этого браузер рисует список во всю длину — при выборе «Все» это десятки экранов,
   которые потом схлопываются в один. Здесь та же величина приблизительно: 100% высоты окна
   минус шапка страницы, подвал списка и строка времени генерации. Скрипт затем уточняет */
@media (min-width: 992px) {
	.list-main .table-responsive {
		max-height: calc(100vh - 185px);
	}
	.list-side {
		max-height: calc(100vh - 140px);
		overflow-y: auto;
	}
}
/* Широкое окно: подвал в одну строку — листалка и кнопки слева, счётчик и «Записей» справа.
   Перенос запрещён, чтобы селектор не уезжал вниз, когда до нехватки места остаются считаные
   пиксели. Блок стоит ПОСЛЕ базовых правил: медиа-запрос специфичности не добавляет */
@media (min-width: 1200px) {
	.list-foot {
		flex-wrap: nowrap;
	}
	.list-pages,
	.list-found,
	.list-records {
		flex-shrink: 0;
	}
}
/* Окно, в которое всё в одну строку не помещается: счётчик уходит на свою строку целиком —
   так же, как на телефоне. Прятать или сокращать его нельзя, это главная цифра списка.
   Порог 1200px: при открытой колонке отбора листалка, три кнопки и селектор занимают
   около 580px, и на счётчик остаётся меньше двухсот */
@media (min-width: 992px) and (max-width: 1199px) {
	.list-found {
		order: 4;
		flex: 1 0 100%;
		margin: 7px 0 0;
		text-align: center;
	}
	/* Селектор остаётся в первой строке и прижат к правому краю: место счётчика освободилось */
	.list-records {
		margin-left: auto;
	}
}
.list-main .pagination {
	margin: 6px 0 0;
}
/* Фильтр с несколькими значениями: кнопка со списком галочек вместо
   многострочного списка, который распирал колонку по высоте */
.list-multi {
	position: relative;
	display: block;
}
/* Крестик «снять все» стоит слева от треугольника. Он вне кнопки — иначе нажатие
   на него открывало бы список. Показывает и прячет его multiText() в modal.js */
.list-multi .list-multi-clear {
	right: 26px;
}
.list-multi .list-multi-btn {
	width: 100%;
	height: 32px;
	padding: 4px 46px 4px 10px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	text-align: left;
}
/* Треугольник закреплён у правого края: иначе он уезжал бы влево от увеличенного
   отступа кнопки и оказывался левее крестика */
.list-multi .list-multi-btn .caret {
	position: absolute;
	top: 14px;
	right: 10px;
	float: none;
	margin-top: 0;
}
.list-multi .dropdown-menu {
	min-width: 100%;
	max-height: 260px;
	overflow-y: auto;
	padding: 4px 0;
}
.list-multi .dropdown-menu label {
	display: block;
	margin: 0;
	padding: 4px 12px;
	color: #333333;
	font-size: 13px;
	font-weight: normal;
	white-space: nowrap;
	cursor: pointer;
}
.list-multi .dropdown-menu label:hover {
	background-color: #f2f2f2;
}
.list-multi .dropdown-menu input {
	margin-right: 8px;
}
/* Телефон и планшет: bootstrap.min.css в проекте собран без адаптивной части (в нём остались
   только @media print), поэтому штатное сворачивание меню не работает — правила ниже добавляют
   его. Вендорный файл не трогаем: его правки потеряются при обновлении Bootstrap.
   Граница 991px, а не 767: на телефоне в горизонтальном положении (около 780px) логотип,
   четыре списка, «Фильтры» и «Admin» в строку не помещались и уезжали на вторую строку,
   съедая и без того низкий экран. Та же граница у раскладки списков — поведение единое */
@media (max-width: 991px) {
	.navbar-header {
		float: none;
	}
	.navbar-toggle {
		display: block;
	}
	.navbar-collapse {
		border-top: 1px solid #e7e7e7;
	}
	.navbar-collapse.collapse {
		display: none !important;
	}
	.navbar-collapse.collapse.in {
		display: block !important;
	}
	.navbar-nav {
		float: none !important;
		margin: 7px -15px;
	}
	.navbar-nav > li {
		float: none;
	}
	.navbar-nav > li > a {
		padding-top: 10px;
		padding-bottom: 10px;
	}
	.navbar-right {
		float: none !important;
	}
	/* Выпадающие списки внутри свёрнутого меню — обычным перечнем, а не всплывающим окном */
	.navbar-nav .open .dropdown-menu {
		position: static;
		float: none;
		width: auto;
		margin-top: 0;
		background-color: transparent;
		border: 0;
		box-shadow: none;
	}
	.navbar-nav .open .dropdown-menu > li > a {
		padding: 6px 15px 6px 30px;
	}
}
/* Планшет и телефон: колонка отбора становится на всю ширину над таблицей
   и прокручивается вместе со страницей, подвал прилипает к низу экрана */
@media (max-width: 991px) {
	.list-layout {
		display: block;
	}
	/* Колонка отбора прокручивается вместе со страницей, высоту не ограничиваем.
	   !important — потому что на широком экране её ставит tableFit() в стиле элемента */
	.list-side {
		width: auto;
		margin-right: 0;
		margin-bottom: 14px;
		max-height: none !important;
	}
	/* Подвал закреплён у низа экрана: страница прокручивается целиком, и без этого
	   до пагинации и селектора «Записей» пришлось бы крутить тысячи строк.
	   Именно fixed, а не sticky: широкая таблица прокручивает страницу ещё и вбок,
	   а подвал должен оставаться на месте */
	.list-foot {
		position: fixed;
		left: 0;
		right: 0;
		bottom: 0;
		z-index: 3;
		margin-top: 0;
		padding: 6px 8px;
		background-color: #ffffff;
		border-top: 1px solid #dddddd;
		box-shadow: 0 -2px 6px rgba(0, 0, 0, 0.12);
	}
	/* Подвал вынут из потока, поэтому место под него освобождаем отступом страницы —
	   иначе он закроет последние строки таблицы и время генерации */
	body {
		padding-bottom: 76px;
	}
	/* Три зоны в одну строку: слева «Записей», по центру переход по страницам,
	   справа «Обновить». Счётчик — подписью под ними, во всю ширину и по центру */
	.list-records {
		order: 1;
		margin: 0;
	}
	.list-pages {
		order: 2;
		margin: 0 auto;
	}
	.list-reload,
	.list-link,
	.list-export {
		order: 3;
		margin: 0 0 0 6px;
	}
	/* Первая кнопка ряда идёт сразу за листалкой, отступ ей не нужен */
	.list-reload {
		margin-left: 0;
	}
	.list-found {
		order: 4;
		flex: 1 0 100%;
		margin: 5px 0 0;
		color: #888888;
		font-size: 12px;
		text-align: center;
	}
	/* Подписи убраны, кнопки и поля уже: иначе строка не помещается в 360px */
	.list-pages-word,
	.list-records label {
		display: none;
	}
	.list-pages .btn {
		width: 28px;
		margin-right: 3px;
	}
	.list-pages .list-pages-input {
		width: 46px;
	}
	.list-pages-text {
		margin: 0 5px;
		font-size: 13px;
	}
	.list-records .form-control {
		width: 64px;
	}
}
/* Телефон: счётчик записей прячем совсем, подвал становится в одну строку и занимает меньше */
@media (max-width: 575px) {
	.list-found {
		display: none;
	}
	/* Ссылка и выгрузка — действия для рабочего места, а не для телефона: в одну строку
	   подвала они не помещаются, а вторая строка съела бы экран */
	.list-link,
	.list-export {
		display: none;
	}
	body {
		padding-bottom: 56px;
	}
}
/* Таблица прокручивается внутри своего блока: шапка страницы, колонка отбора и подвал
   с пагинацией остаются на месте. Высоту блока подбирает tableFit() в modal.js */
.list-main .table-responsive {
	margin-bottom: 0;
	border: 1px solid #e2e2e2;
	border-radius: 0;
	overflow: auto;
}
/* На узком экране обёртка тоже прокручивается вбок, а страница — нет. Пробовали наоборот
   (снять прокрутку с обёртки и отдать её странице, чтобы шапку держал sticky): в эмуляции
   Chrome на ПК работает, на настоящем телефоне рассыпается. Причина — на телефоне fixed
   и sticky привязаны к layout-viewport, а страница, которая ездит вбок, делает его шире
   экрана. Шапку на узком экране рисует копией скрипт, см. tableHeadBuild() в modal.js */
/* border-collapse оставлен обычным: на таблице в тысячи строк раскладка с separate
   заметно медленнее, а рамку прилипшей шапки рисует тень */
.list-main .table {
	margin-bottom: 0;
}
/* Шапка таблицы не уезжает при прокрутке */
.list-main .table > thead > tr > th {
	position: sticky;
	top: 0;
	z-index: 2;
	background-color: #ffffff;
	box-shadow: inset 0 -2px 0 #dddddd;
	border-bottom: 0;
}
.list-main .table > thead > tr > th {
	padding: 8px;
	white-space: nowrap;
	color: #333333;
	font-weight: 600;
}
/* Строка «ничего не найдено» вместо данных: таблица с заголовками остаётся на месте */
.list-main .table > tbody > tr > td.list-empty {
	padding: 22px 8px;
	color: #999999;
	text-align: center;
}
/* Колонка, которая не должна забирать свободную ширину таблицы: ширина 1% заставляет
   браузер отдать ей ровно по содержимому, а остаток разойдётся по текстовым колонкам.
   Нужна там, где в ячейке стоит элемент постоянного размера — например проигрыватель
   записи разговора в списке АТС: без этого весь запас ширины уходил в его столбец
   и справа оставалось пустое поле */
.list-main .table .list-cell-shrink {
	width: 1%;
	white-space: nowrap;
}
/* Проигрыватель записи разговора: ширину задаём явно. В колонке, ужатой по содержимому,
   элемент без своей ширины сжимается до нечитаемого. Кнопки, время и громкость у проигрывателя
   постоянного размера (около 185px на всё), поэтому вся добавленная ширина достаётся полосе
   перемотки: при 260px на неё оставалось около 75px и перематывать было неудобно, при 380px она вышла
   длиннее нужного. 320px — середина: около 135px на полосу */
.list-main .table audio {
	width: 320px;
	vertical-align: middle;
}
/* Плотнее, чем по умолчанию: на экран влезает больше строк, читать удобнее */
.list-main .table > tbody > tr > td {
	padding: 6px 8px;
	vertical-align: middle;
}
/* Плавающая шапка таблицы для узкого экрана: копия строки заголовков, которую показывает
   tableHeadBuild() в modal.js, когда настоящая шапка ушла за верх экрана. Лежит внутри
   .list-main, чтобы к ней применились те же стили колонок и стрелок сортировки.
   Ширину, положение и сдвиг по горизонтали ставит скрипт */
.table-head-float {
	display: none;
	position: fixed;
	top: 0;
	z-index: 4;
	overflow: hidden;
	background-color: #ffffff;
	box-shadow: 0 2px 6px rgba(0, 0, 0, 0.14);
}

/* ------------------------------------------------------------------------- */
/* Быстрый поиск абонента: окно поверх страницы, вызывается кнопкой в шапке.
   Своя разметка и свои стили — в bootstrap.min.css этого проекта модального окна нет */
.abonent-search {
	display: none;
}
.abonent-search.abonent-search-on {
	display: block;
}
.abonent-search-lock {
	overflow: hidden;
}
.abonent-search-back {
	position: fixed;
	left: 0;
	right: 0;
	top: 0;
	bottom: 0;
	z-index: 1040;
	background-color: rgba(0, 0, 0, 0.45);
}
/* Окно у верхней трети экрана, а не по центру: глаз ищет строку ввода там,
   и при появлении результатов окно растёт вниз, не прыгая */
.abonent-search-box {
	position: fixed;
	left: 50%;
	top: 90px;
	z-index: 1041;
	width: 640px;
	max-width: calc(100% - 24px);
	margin-left: -320px;
	border-radius: 8px;
	background-color: #ffffff;
	box-shadow: 0 12px 40px rgba(0, 0, 0, 0.28);
	overflow: hidden;
}
.abonent-search-head {
	position: relative;
	border-bottom: 1px solid #e6e6e6;
}
.abonent-search-icon {
	position: absolute;
	left: 18px;
	top: 21px;
	color: #aaaaaa;
	font-size: 16px;
}
.abonent-search-input {
	width: 100%;
	height: 58px;
	padding: 0 46px 0 46px;
	border: 0;
	outline: none;
	font-size: 17px;
	color: #333333;
}
.abonent-search-close {
	position: absolute;
	right: 10px;
	top: 12px;
	width: 34px;
	height: 34px;
	padding: 0;
	border: 0;
	border-radius: 17px;
	background-color: transparent;
	color: #999999;
	font-size: 22px;
	line-height: 30px;
}
.abonent-search-close:hover {
	background-color: #f0f0f0;
	color: #333333;
}
.abonent-search-body {
	display: flex;
	align-items: center;
	padding: 16px 18px;
}
/* Поля поиска — те же три, что в панели списка абонентов */
.abonent-search-fields {
	flex: 1 1 auto;
	min-width: 0;
}
.abonent-search-fields label {
	margin: 0 16px 0 0;
	font-weight: normal;
	color: #444444;
	white-space: nowrap;
}
.abonent-search-fields input {
	margin-right: 5px;
}
.abonent-search-go {
	flex: 0 0 auto;
	min-width: 110px;
}
.abonent-search-foot {
	padding: 8px 18px;
	border-top: 1px solid #e6e6e6;
	background-color: #fafafa;
	color: #999999;
	font-size: 11px;
}
.abonent-search-foot span {
	margin-right: 14px;
}
.abonent-search-foot b {
	padding: 1px 5px;
	border: 1px solid #dddddd;
	border-radius: 3px;
	background-color: #ffffff;
	color: #666666;
	font-weight: 600;
}
/* Телефон: окно занимает почти весь экран, подсказка про клавиши не нужна */
@media (max-width: 767px) {
	.abonent-search-box {
		left: 8px;
		right: 8px;
		top: 8px;
		width: auto;
		max-width: none;
		margin-left: 0;
	}
	/* Поля и кнопка в столбик: в строку они на телефоне не помещаются */
	.abonent-search-body {
		display: block;
	}
	.abonent-search-fields label {
		display: block;
		margin: 0 0 10px;
		padding: 4px 0;
	}
	.abonent-search-go {
		width: 100%;
		padding: 10px;
	}
	.abonent-search-foot {
		display: none;
	}
	/* Поле ввода крупнее: мелкий шрифт заставляет мобильный браузер увеличивать страницу
	   при установке курсора, и после закрытия окна она остаётся увеличенной */
	.abonent-search-input {
		height: 52px;
		font-size: 16px;
	}
}

/* --- Карточка устройства над списком портов ------------------------------- */

.device-card {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 22px;
	margin-bottom: 10px;
	padding: 10px 14px;
	background-color: var(--card);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
}

.device-card-item {
	display: flex;
	flex-direction: column;
}

.device-card-label {
	color: var(--muted);
	font-size: 11px;
	line-height: 1.3;
}

.device-card-value {
	color: var(--text-strong);
	font-size: 13px;
	font-weight: 600;
}

.device-card-back {
	margin-left: auto;
}

/* --- Формы разделов ------------------------------------------------------- */

.form-card {
	max-width: 640px;
	padding: 18px;
	background-color: var(--card);
	border: 1px solid var(--border);
	border-radius: var(--radius);
}

.form-card p {
	margin-bottom: 10px;
}

.form-row {
	margin-bottom: 14px;
}

.form-row > label {
	display: block;
	margin-bottom: 4px;
	color: var(--muted);
	font-size: 12px;
	font-weight: 600;
}

.form-hint {
	margin-top: 4px;
	color: var(--muted);
	font-size: 12px;
	line-height: 1.4;
}

.form-static {
	padding: 6px 0;
	color: var(--text-strong);
	font-weight: 600;
}

/* --- Дерево прав группы --------------------------------------------------- */

.rights-tree {
	max-height: 460px;
	padding: 10px 12px;
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	background-color: #FBFDFB;
	overflow-y: auto;
}

.rights-item {
	display: block;
	padding: 3px 0;
	font-size: 13px;
	font-weight: 400;
	cursor: pointer;
}

.rights-item:hover {
	color: var(--brand);
}

.rights-item input {
	margin-right: 6px;
}

/* Отступ по уровню вложенности: видно, что действие относится к разделу */
.rights-level-1 {
	padding-left: 24px;
}

.rights-level-2 {
	padding-left: 48px;
}

.rights-level-3 {
	padding-left: 72px;
}

.rights-id {
	display: inline-block;
	min-width: 30px;
	color: var(--muted);
	font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
	font-size: 11px;
}
