Files
KindClustersDashboard/app/static/style.css
T
Sergey Antropoff 52538d9816 Панель: редактирование конфига кластера, reapply при старте, UI и таблица
- PUT/GET конфигурации кластера, страница редактирования и модалка после сохранения
- После смены kind-config: флаг в meta и start_cluster_reapply (kind delete + create)
- Старт/стоп: полноэкранный спиннер до завершения job; модалки и документация API
- Таблица кластеров: колонка Имя 40% при table-layout fixed; чекбоксы без width 100%
- Карточки ресурсов узлов на странице кластера: до 3 в ряд; прочие правки стилей и dashboard.js
2026-04-04 10:49:40 +03:00

2717 lines
59 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Минимальные стили веб-интерфейса Kind Clusters Dashboard.
Автор: Сергей Антропов — https://devops.org.ru */
/* Тема: тёмная по умолчанию; светлая — html[data-theme="light"]. Переключатель в шапке + localStorage. */
html {
font-family: system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, sans-serif;
}
html:not([data-theme="light"]) {
color-scheme: dark;
--bg: #0f1419;
--fg: #e7ecf1;
--muted: #8b98a5;
--card: #1a2332;
--accent: #3b82f6;
--border: #2f3d52;
}
/* Светлая тема: основной текст и акценты в синей гамме (как тёмная), без «чистого» чёрного */
html[data-theme="light"] {
color-scheme: light;
--bg: #eef2fb;
--fg: #172c46;
--muted: #5a6f8f;
--card: #ffffff;
--border: #b8c9e8;
--accent: #3b82f6;
}
body {
margin: 0;
padding: 0;
background: var(--bg);
color: var(--fg);
line-height: 1.45;
}
body.modal-open {
overflow: hidden;
}
/* Пропуск к основному содержимому (a11y) */
.skip-link {
position: absolute;
left: -9999px;
top: 0.5rem;
z-index: 200;
padding: 0.5rem 1rem;
background: var(--accent);
color: #fff;
border-radius: 6px;
font-weight: 600;
}
.skip-link:focus {
left: 0.5rem;
outline: 2px solid var(--fg);
outline-offset: 2px;
}
/* Верхняя навигация */
.top-nav {
border-bottom: 1px solid var(--border);
background: var(--card);
}
.top-nav-inner {
max-width: 72rem;
margin: 0 auto;
padding: 0.65rem 1.25rem;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 0.75rem;
}
.nav-brand {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.5rem;
}
.nav-brand-link {
text-decoration: none;
color: inherit;
}
.nav-brand-link:hover .nav-title {
color: var(--accent);
}
.nav-brand-link:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 3px;
border-radius: 6px;
}
.nav-logo-img {
width: 1.75rem;
height: 1.75rem;
flex-shrink: 0;
display: block;
}
.nav-title {
font-weight: 700;
font-size: 1.05rem;
}
.nav-tag {
font-size: 0.8rem;
}
/* Шапка: один flex-ряд, все пилюли + API + тема с align-items: center */
.nav-links {
display: flex;
flex-wrap: nowrap;
align-items: center;
gap: 0.45rem;
}
.nav-links.top-nav-actions {
justify-content: flex-end;
flex: 1 1 auto;
min-width: 0;
/* Не overflow-x: здесь — иначе обрезается .nav-dropdown__menu (absolute под кнопкой API). */
overflow: visible;
}
/* Горизонтальная прокрутка только подписей «Панель» / «Документация», без выпадающего меню. */
.nav-links-scroll {
display: flex;
flex-wrap: nowrap;
align-items: center;
gap: 0.45rem;
min-width: 0;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scrollbar-width: thin;
/*
* При overflow-x: auto вертикаль становится auto — обрезает translateY(-1px) и тень у .nav-pill:hover.
* Внутренний padding даёт место сверху/снизу; API вне .nav-links-scroll, там обрезки не было.
* z-index как у .nav-dropdown — общий stacking context при overflow.
*/
padding-top: 0.45rem;
padding-bottom: 0.45rem;
position: relative;
z-index: 160;
}
/* Выпадающее меню «API»: Swagger, ReDoc, Health в отдельном окне */
.nav-dropdown {
position: relative;
z-index: 160;
display: inline-flex;
align-items: center;
flex-shrink: 0;
align-self: center;
}
.nav-dropdown__trigger {
font: inherit;
cursor: pointer;
margin: 0;
}
.nav-dropdown__trigger::after {
content: "▾";
margin-left: 0.35rem;
font-size: 0.72em;
opacity: 0.85;
display: inline-block;
transition: transform 0.18s ease;
vertical-align: middle;
}
.nav-dropdown--open .nav-dropdown__trigger::after {
transform: rotate(-180deg);
}
.nav-dropdown__menu {
position: absolute;
top: calc(100% + 0.35rem);
right: 0;
z-index: 160;
min-width: 11rem;
margin: 0;
padding: 0.35rem 0;
list-style: none;
background: var(--card);
border: 1px solid var(--border);
border-radius: 10px;
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.35);
}
html[data-theme="light"] .nav-dropdown__menu {
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.12);
}
.nav-dropdown__menu[hidden] {
display: none !important;
}
.nav-dropdown__menu li {
margin: 0;
}
.nav-dropdown__link {
display: flex;
align-items: center;
width: 100%;
box-sizing: border-box;
padding: 0.48rem 1rem;
font-size: 0.8125rem;
font-weight: 600;
text-decoration: none;
color: var(--fg);
background: transparent;
border: none;
cursor: pointer;
font-family: inherit;
}
.nav-dropdown__link:hover,
.nav-dropdown__link:focus-visible {
background: rgba(59, 130, 246, 0.14);
color: var(--accent);
outline: none;
}
.nav-dropdown__link.nav-pill--ext::after {
content: "↗";
margin-left: auto;
padding-left: 0.5rem;
font-size: 0.72em;
opacity: 0.72;
font-weight: 700;
}
/* Переключатель светлая / тёмная тема (в конце шапки, высота как у пилюль) */
.theme-toggle {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.42rem 0.75rem;
min-width: 2.5rem;
border-radius: 999px;
font-size: 0.8125rem;
font-weight: 600;
border: 1px solid var(--border);
background: rgba(0, 0, 0, 0.18);
color: var(--fg);
cursor: pointer;
transition:
background 0.18s ease,
border-color 0.18s ease,
color 0.18s ease,
box-shadow 0.18s ease;
}
html[data-theme="light"] .theme-toggle {
background: rgba(59, 130, 246, 0.1);
border-color: rgba(59, 130, 246, 0.28);
color: var(--accent);
}
.theme-toggle:hover {
border-color: var(--accent);
background: rgba(59, 130, 246, 0.14);
color: var(--accent);
box-shadow: 0 2px 12px rgba(59, 130, 246, 0.2);
}
.theme-toggle:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
.theme-toggle__icon {
display: block;
width: 1.1rem;
height: 1.1rem;
flex-shrink: 0;
}
html[data-theme="light"] .theme-toggle__icon--sun {
display: none;
}
html[data-theme="light"] .theme-toggle__icon--moon {
display: block;
}
html:not([data-theme="light"]) .theme-toggle__icon--sun {
display: block;
}
html:not([data-theme="light"]) .theme-toggle__icon--moon {
display: none;
}
/* Визуально кнопка темы сидела ниже пилюль (<a> vs <button>); поднимаем на 0.75rem */
.theme-toggle--nav-end {
flex-shrink: 0;
align-self: center;
padding-left: 0.65rem;
padding-right: 0.65rem;
min-height: calc(0.8125rem * 1.35 + 0.84rem);
box-sizing: border-box;
transform: translateY(-0.3rem);
}
/* Пункты меню: компактные «пилюли» */
.nav-link.nav-pill {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.42rem 0.95rem;
border-radius: 999px;
font-size: 0.8125rem;
font-weight: 600;
letter-spacing: 0.02em;
text-decoration: none;
border: 1px solid var(--border);
background: rgba(0, 0, 0, 0.18);
color: var(--fg);
transition:
background 0.18s ease,
border-color 0.18s ease,
color 0.18s ease,
box-shadow 0.18s ease,
transform 0.12s ease;
}
.nav-link.nav-pill:hover {
text-decoration: none;
border-color: var(--accent);
background: rgba(59, 130, 246, 0.14);
color: var(--accent);
box-shadow: 0 2px 12px rgba(59, 130, 246, 0.2);
transform: translateY(-1px);
}
.nav-link.nav-pill:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
/* Активный раздел: «Панель» на дашборде или «Документация» на /documentation */
.nav-link.nav-pill.nav-pill--active:not(.nav-pill--ext) {
border-color: rgba(59, 130, 246, 0.85);
box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.35), 0 2px 14px rgba(59, 130, 246, 0.18);
background: rgba(59, 130, 246, 0.16);
color: #93c5fd;
}
html[data-theme="light"] .nav-link.nav-pill {
background: rgba(59, 130, 246, 0.1);
border-color: rgba(59, 130, 246, 0.28);
color: var(--fg);
}
html[data-theme="light"] .nav-link.nav-pill.nav-pill--active:not(.nav-pill--ext) {
color: #1d4ed8;
background: rgba(59, 130, 246, 0.18);
border-color: rgba(37, 99, 235, 0.45);
}
/* Внешние окна: иконка «новое окно» */
.nav-link.nav-pill--ext::after {
content: "↗";
margin-left: 0.35rem;
font-size: 0.72em;
opacity: 0.72;
font-weight: 700;
}
/* Обычная ссылка без пилюли (если понадобится) */
.nav-link:not(.nav-pill) {
color: var(--accent);
text-decoration: none;
font-size: 0.9rem;
}
.nav-link:not(.nav-pill):hover {
text-decoration: underline;
}
.app-main {
max-width: 72rem;
margin: 0 auto;
padding: 1.25rem;
outline: none;
}
.app-footer {
max-width: 72rem;
margin: 0 auto;
padding: 1rem 1.25rem 2rem;
border-top: 1px solid var(--border);
font-size: 0.85rem;
}
.footer-inner {
text-align: center;
}
.footer-line {
margin: 0 0 0.5rem;
}
.footer-copyright {
margin: 0;
font-size: 0.9rem;
color: var(--fg);
}
.footer-copyright a {
color: var(--accent);
font-weight: 600;
}
/* Верхний ряд: CTA «Создать кластер» и статистика по ~50% ширины */
.top-dashboard-row {
display: grid;
gap: 1rem;
margin-bottom: 1rem;
align-items: stretch;
}
@media (min-width: 960px) {
.top-dashboard-row {
grid-template-columns: 1fr 1fr;
}
}
/* Левая карточка — переход к форме создания */
.cta-hero-card {
margin-bottom: 0;
display: flex;
align-items: center;
justify-content: center;
min-height: min(16rem, 42vh);
}
.cta-hero-inner {
text-align: center;
padding: 1.35rem 1.25rem;
width: 100%;
max-width: 26rem;
margin: 0 auto;
}
.cta-hero-card .page-title {
margin: 0 0 0.5rem;
font-size: clamp(1.35rem, 2.5vw, 1.65rem);
}
.cta-hero-lead {
margin: 0 0 2.15rem;
font-size: 0.92rem;
line-height: 1.5;
max-width: 22rem;
margin-left: auto;
margin-right: auto;
}
.cta-hero-inner .btn-cta-large {
margin-top: 0.15rem;
}
.stats-side-card {
display: flex;
flex-direction: column;
gap: 0.85rem;
}
.stats-side-card h2 {
margin: 0;
flex-shrink: 0;
font-size: 1.05rem;
}
/* Пояснение: узлы kind и метрики идут через Docker или Podman (CONTAINER_CLI) */
.stats-engine-hint {
margin: 0;
flex-shrink: 0;
font-size: 0.8rem;
line-height: 1.35;
}
/* Одна карточка «Ошибка» на всю ширину блока статистики (health или /stats) */
.stats-failure-wrap {
width: 100%;
flex-shrink: 0;
}
.stats-failure-card {
width: 100%;
box-sizing: border-box;
min-height: 4.75rem;
padding: 0.85rem 0.65rem;
}
/* Среда: Docker API · Kind · Kubectl · Каталогов — один ряд, 4 колонки */
.stats-env-cards {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 0.65rem;
flex-shrink: 0;
}
@media (max-width: 520px) {
.stats-env-cards {
grid-template-columns: 1fr;
}
}
.stats-env-placeholder {
grid-column: 1 / -1;
margin: 0;
font-size: 0.85rem;
text-align: center;
padding: 0.5rem 0;
}
.stats-env-card {
min-height: 4.5rem;
padding: 0.65rem 0.4rem;
}
.stats-env-card--ok {
border-color: rgba(34, 197, 94, 0.45);
background: rgba(34, 197, 94, 0.08);
}
.stats-env-card--bad {
border-color: rgba(239, 68, 68, 0.45);
background: rgba(239, 68, 68, 0.08);
}
.stats-env-card--bad .stats-tile__value {
color: #f87171;
}
html[data-theme="light"] .stats-env-card--bad .stats-tile__value {
color: #b91c1c;
}
.stats-env-card__detail {
display: block;
font-size: 0.7rem;
line-height: 1.3;
margin-top: 0.35rem;
text-align: center;
word-break: break-word;
}
.stats-env-card--metric {
border-color: var(--border);
background: rgba(0, 0, 0, 0.08);
}
html[data-theme="light"] .stats-env-card--metric {
background: rgba(59, 130, 246, 0.07);
}
/* Метрики: по 4 карточки в ряд (4 метрики — один ряд) */
.stats-metrics-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 0.65rem;
flex: 1 1 auto;
align-content: start;
}
@media (max-width: 520px) {
.stats-metrics-grid {
grid-template-columns: repeat(2, 1fr);
}
}
.stats-tile {
border-radius: 10px;
padding: 0.72rem 0.45rem;
text-align: center;
display: flex;
flex-direction: column;
gap: 0.3rem;
justify-content: center;
min-height: 4.1rem;
border: 1px solid var(--border);
background: rgba(0, 0, 0, 0.1);
}
html[data-theme="light"] .stats-tile {
background: rgba(59, 130, 246, 0.07);
}
.stats-tile__value {
font-size: 1.28rem;
font-weight: 700;
font-variant-numeric: tabular-nums;
color: var(--accent);
line-height: 1.15;
}
.stats-tile__label {
font-size: 0.68rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.045em;
color: var(--muted);
line-height: 1.25;
}
/* Метрики узла (общие стили: донаты на главной и раскрытие под строкой кластера) */
.stats-node-res {
margin-bottom: 0.45rem;
padding: 0.35rem 0.45rem;
border-radius: 6px;
background: rgba(0, 0, 0, 0.12);
border: 1px solid var(--border);
}
.stats-node-res code {
display: block;
font-size: 0.76rem;
margin-bottom: 0.25rem;
word-break: break-all;
}
.stats-node-res__metrics {
margin: 0;
padding-left: 1rem;
list-style: disc;
}
.stats-node-res__metrics li {
margin: 0.1rem 0;
}
.stats-node-res__metrics strong {
font-weight: 600;
color: var(--muted);
}
html[data-theme="light"] .stats-node-res {
background: rgba(59, 130, 246, 0.07);
}
.btn-cta-large {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: min(22rem, 100%);
margin-top: 0;
padding: 0.95rem 2.25rem;
font-size: 1.15rem;
font-weight: 650;
border-radius: 12px;
text-decoration: none;
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
border: 1px solid transparent;
background: var(--accent);
color: #fff;
cursor: pointer;
}
a.btn-cta-large:hover {
filter: brightness(1.08);
}
/* Сводка-денаты по узлам */
.aggregate-donuts-card {
margin-bottom: 1rem;
}
.donuts-card-title {
margin: 0 0 0.75rem;
}
.donut-grid {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-evenly;
align-items: flex-start;
gap: 1rem 1.5rem;
overflow-x: auto;
padding-bottom: 0.35rem;
-webkit-overflow-scrolling: touch;
scrollbar-width: thin;
}
.donut-item {
flex: 0 0 auto;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
gap: 0.35rem;
}
.donut-svg {
width: 6.5rem;
height: 6.5rem;
flex-shrink: 0;
}
.donut-track {
stroke: var(--border);
}
.donut-fill {
stroke: var(--accent);
stroke-linecap: round;
}
.donut-meta {
display: flex;
flex-direction: column;
gap: 0.12rem;
max-width: 11rem;
}
.donut-meta__title {
font-size: 0.72rem;
font-weight: 650;
text-transform: uppercase;
letter-spacing: 0.03em;
color: var(--muted);
}
.donut-meta__val {
font-size: 0.88rem;
font-weight: 600;
word-break: break-word;
}
.donut-meta__sub {
font-size: 0.75rem;
}
.aggregate-donuts-placeholder {
margin: 0;
font-size: 0.9rem;
line-height: 1.45;
max-width: 40rem;
}
.cluster-nodes-resources__empty {
margin: 0.25rem 0 0;
font-size: 0.85rem;
}
/* Карточки узлов: полосы CPU, RAM %, память от лимита, сеть, диск + подсказка справа */
.cluster-nodes-resources__cards-row {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-items: stretch;
gap: 0.75rem;
margin-top: 0.35rem;
overflow-x: auto;
padding-bottom: 0.25rem;
-webkit-overflow-scrolling: touch;
scrollbar-width: thin;
}
.cluster-node-res-card {
flex: 0 0 auto;
width: min(17.5rem, 88vw);
min-width: 14rem;
box-sizing: border-box;
padding: 0.55rem 0.65rem 0.5rem;
border-radius: 10px;
border: 1px solid var(--border);
background: rgba(0, 0, 0, 0.12);
border-left: 3px solid var(--accent);
}
html[data-theme="light"] .cluster-node-res-card {
background: rgba(59, 130, 246, 0.08);
}
.cluster-node-res-card__head {
margin: 0 0 0.45rem;
}
.cluster-node-res-card__head code {
font-size: 0.78rem;
word-break: break-all;
line-height: 1.35;
}
.cluster-node-res-card__bars {
display: flex;
flex-direction: column;
gap: 0.35rem;
}
.cluster-node-res-card__bar-row {
display: grid;
grid-template-columns: 3rem minmax(0, 1fr) minmax(2.8rem, 4.5rem);
align-items: center;
gap: 0.3rem 0.35rem;
}
.cluster-node-res-card__bar-hint {
font-size: 0.62rem;
line-height: 1.2;
text-align: right;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
}
.cluster-node-res-card__bar-label {
font-size: 0.68rem;
font-weight: 650;
text-transform: uppercase;
letter-spacing: 0.02em;
color: var(--muted);
}
.cluster-node-res-card__bar-track {
height: 0.45rem;
border-radius: 999px;
background: rgba(255, 255, 255, 0.08);
overflow: hidden;
}
html[data-theme="light"] .cluster-node-res-card__bar-track {
background: rgba(0, 0, 0, 0.06);
}
.cluster-node-res-card__bar-fill {
height: 100%;
border-radius: inherit;
background: linear-gradient(90deg, rgba(59, 130, 246, 0.55), var(--accent));
min-width: 2px;
transition: width 0.25s ease;
}
.cluster-node-res-card__foot {
margin-top: 0.45rem;
font-size: 0.72rem;
line-height: 1.4;
word-break: break-word;
}
.cluster-create-hero {
margin-bottom: 1.35rem;
}
/* Карточка формы: чуть плотнее внутри, заголовок отступает от полей */
.card.create-cluster-card {
padding: 0.85rem 1rem 1rem;
margin-bottom: 1rem;
}
.create-cluster-card__title {
margin: 0 0 1rem;
padding: 0;
font-size: 1.02rem;
}
/* Сетка 2×2: имя | тег, затем подсказка на всю ширину, workers | версия; выравнивание по нижнему краю ячеек */
.create-form-grid {
display: grid;
gap: 0.4rem 1.15rem;
margin-top: 0;
}
.create-form-field {
display: flex;
flex-direction: column;
gap: 0.2rem;
min-width: 0;
}
.create-form-field > label {
margin: 0;
font-size: 0.8125rem;
line-height: 1.3;
font-weight: 600;
}
.create-form-grid .create-form-field input:not([type="checkbox"]),
.create-form-grid .create-form-field select {
width: 100%;
max-width: none;
margin: 0;
padding: 0.35rem 0.5rem;
min-height: 2.3rem;
box-sizing: border-box;
line-height: 1.25;
}
@media (min-width: 640px) {
.create-form-grid {
grid-template-columns: 1fr 1fr;
align-items: end;
}
}
.create-form-span {
grid-column: 1 / -1;
}
/* Ссылка на актуальные теги kindest/node (Docker Hub), новая вкладка */
.create-form-doc-link {
color: var(--accent);
font-weight: 650;
text-decoration: none;
}
.create-form-doc-link:hover {
text-decoration: underline;
text-underline-offset: 2px;
}
.create-form-doc-link:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
border-radius: 3px;
}
.create-form-doc-link__ext {
margin-left: 0.12rem;
font-size: 0.82em;
font-weight: 700;
color: var(--accent);
opacity: 0.85;
}
.create-form-label-rest {
font-weight: 600;
}
.create-ver-hint {
margin: 0;
font-size: 0.8rem;
line-height: 1.35;
}
.create-ver-hint--full {
grid-column: 1 / -1;
margin: 0.1rem 0 0.25rem;
}
.create-form-grid .create-actions {
margin-top: 0.35rem;
padding-top: 0.15rem;
width: 100%;
justify-content: center;
}
.create-form-grid .create-actions button {
margin-top: 0;
}
/* Одна карточка: заголовок + описание + строка состояния среды */
.hero-panel {
margin-bottom: 1rem;
}
.hero-panel-main {
margin-bottom: 0.85rem;
}
.hero-panel .page-title {
margin: 0 0 0.35rem;
}
.hero-panel .page-lead {
margin: 0;
max-width: 48rem;
}
.hero-panel-status {
margin: 0;
border-radius: 8px;
padding: 0.65rem 0.85rem;
font-size: 0.9rem;
border: 1px solid var(--border);
}
.hero-panel-status.ok {
border-color: #15803d;
background: rgba(34, 197, 94, 0.12);
}
.hero-panel-status.degraded {
border-color: #b45309;
background: rgba(245, 158, 11, 0.12);
}
.hero-panel-status.err {
border-color: #b91c1c;
background: rgba(239, 68, 68, 0.12);
}
/* Прогресс создания кластера */
.create-progress-wrap {
margin-top: 1rem;
padding-top: 0.75rem;
border-top: 1px solid var(--border);
}
.create-progress-hint {
margin: 0 0 0.65rem;
font-size: 0.85rem;
}
.progress-track {
height: 0.65rem;
border-radius: 999px;
background: rgba(0, 0, 0, 0.25);
border: 1px solid var(--border);
overflow: hidden;
}
.progress-bar {
height: 100%;
border-radius: 999px;
background: linear-gradient(90deg, var(--accent), #60a5fa);
transition: width 0.35s ease;
}
.progress-label {
margin: 0.45rem 0 0.65rem;
font-size: 0.88rem;
min-height: 1.35rem;
}
#create-progress-wrap .btn-secondary {
margin-top: 0;
}
/* Журнал kind create в панели прогресса (потоковые строки из API) */
.job-log-panel-wrap {
margin: 0 0 0.65rem;
}
.job-log-label {
display: block;
font-size: 0.8rem;
margin-bottom: 0.25rem;
}
.job-log-panel {
margin: 0;
max-height: min(55vh, 420px);
overflow: auto;
padding: 0.5rem 0.65rem;
font-size: 0.78rem;
line-height: 1.35;
background: rgba(0, 0, 0, 0.2);
border: 1px solid var(--border);
border-radius: 6px;
white-space: pre-wrap;
word-break: break-word;
}
/* Заголовок блока заданий + кнопка очистки */
.jobs-card-toolbar {
margin-bottom: 0.65rem;
}
.jobs-card-title {
margin: 0;
font-size: 1.15rem;
line-height: 1.3;
}
.page-intro {
margin-bottom: 1rem;
}
.page-title {
margin: 0 0 0.35rem;
font-size: 1.35rem;
}
.page-lead {
margin: 0;
max-width: 42rem;
}
.toolbar {
margin-bottom: 1rem;
}
/* Тост уведомлений */
.toast {
position: fixed;
top: 1rem;
right: 1rem;
z-index: 150;
max-width: min(22rem, calc(100vw - 2rem));
padding: 0.65rem 1rem;
border-radius: 8px;
border: 1px solid var(--border);
background: var(--card);
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.25);
font-size: 0.9rem;
}
.toast-ok {
border-color: #15803d;
}
.toast-error {
border-color: #b91c1c;
}
/* Бейджи статусов */
.badge {
display: inline-block;
padding: 0.15rem 0.45rem;
border-radius: 999px;
font-size: 0.75rem;
font-weight: 600;
border: 1px solid var(--border);
background: rgba(0, 0, 0, 0.15);
}
html[data-theme="light"] .badge {
background: rgba(59, 130, 246, 0.12);
}
.badge-ok {
border-color: #15803d;
color: #4ade80;
}
/* Светлая тема: насыщенный зелёный текст и фон — иначе «Запущен» сливается с белым карточным фоном */
html[data-theme="light"] .badge-ok {
border-color: #166534;
color: #14532d;
background: rgba(22, 101, 52, 0.12);
}
.badge-err {
border-color: #b91c1c;
color: #f87171;
}
.badge-run {
border-color: #b45309;
color: #fbbf24;
}
.badge-cancelled {
border-color: #6b7280;
color: #d1d5db;
}
.badge-stopped {
border-color: #b45309;
color: #fcd34d;
}
.cluster-name {
font-weight: 600;
}
/* Состояние загрузки таблиц */
.job-details {
margin-top: 0.75rem;
border: 1px solid var(--border);
border-radius: 8px;
padding: 0.5rem 0.75rem;
background: rgba(0, 0, 0, 0.12);
}
html[data-theme="light"] .job-details {
background: rgba(59, 130, 246, 0.08);
}
.job-details summary {
cursor: pointer;
font-size: 0.9rem;
font-weight: 600;
}
.job-json-pre {
max-height: 12rem;
margin-top: 0.5rem;
}
/* Спиннер в модалке */
.modal-head {
margin-bottom: 0.5rem;
align-items: flex-start;
}
.modal-head--cluster {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.65rem;
margin-bottom: 0.65rem;
text-align: center;
}
.modal-title-text--center {
width: 100%;
text-align: center;
padding-right: 0;
flex: none;
}
.modal-toolbar {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: 0.65rem 1rem;
}
.modal-title-text {
margin: 0;
font-size: 1.05rem;
flex: 1;
padding-right: 0.5rem;
}
.modal-sub {
margin: 0 0 0.75rem;
}
.modal-section-title {
margin: 0.5rem 0 0;
font-size: 0.85rem;
}
.modal-spinner {
display: flex;
align-items: center;
justify-content: center;
gap: 0.65rem;
padding: 1rem 0;
}
.spinner {
width: 1.5rem;
height: 1.5rem;
border: 3px solid var(--border);
border-top-color: var(--accent);
border-radius: 50%;
animation: spin 0.7s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
button:disabled,
input:disabled,
select:disabled {
opacity: 0.55;
cursor: not-allowed;
}
button:focus-visible,
a:focus-visible,
input:focus-visible,
select:focus-visible,
summary:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.header h1 {
margin: 0 0 0.25rem;
font-size: 1.5rem;
}
.muted {
color: var(--muted);
}
.grid {
display: grid;
gap: 1rem;
margin: 1.25rem 0;
}
@media (min-width: 900px) {
.grid {
grid-template-columns: 1fr 1fr;
align-items: start;
}
}
.card {
background: var(--card);
border: 1px solid var(--border);
border-radius: 10px;
padding: 1rem 1.1rem;
}
.card h2 {
margin-top: 0;
font-size: 1.1rem;
}
label {
display: block;
margin: 0.65rem 0 0.25rem;
font-size: 0.9rem;
}
input,
select,
button {
font: inherit;
}
input:not([type="checkbox"]),
select {
width: 100%;
max-width: 28rem;
padding: 0.45rem 0.55rem;
border-radius: 6px;
border: 1px solid var(--border);
background: transparent;
color: inherit;
}
/* Чекбоксы: без растягивания на ширину полей text/select */
input[type="checkbox"] {
width: auto;
max-width: none;
}
button {
margin-top: 0.75rem;
padding: 0.45rem 0.85rem;
border-radius: 6px;
border: 1px solid var(--border);
background: var(--accent);
color: #fff;
cursor: pointer;
}
button:hover {
filter: brightness(1.08);
}
.row {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
align-items: center;
}
.row.spread {
justify-content: space-between;
align-items: center;
}
.mono {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 0.85rem;
white-space: pre-wrap;
word-break: break-word;
background: rgba(0, 0, 0, 0.2);
padding: 0.6rem;
border-radius: 6px;
max-height: 14rem;
overflow: auto;
}
html[data-theme="light"] .mono {
background: rgba(59, 130, 246, 0.1);
}
.table-wrap {
overflow-x: auto;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 0.9rem;
}
th .th-hint {
font-weight: 500;
opacity: 0.7;
font-size: 0.82em;
}
th,
td {
border-bottom: 1px solid var(--border);
padding: 0.45rem 0.35rem;
text-align: left;
vertical-align: top;
}
.msg {
margin-top: 0.5rem;
}
.hidden {
display: none;
}
.footer {
margin-top: 2rem;
font-size: 0.9rem;
}
.footer a {
color: var(--accent);
}
/* Плашка состояния среды (Docker/Podman, kind, kubectl) */
.status-banner {
border-radius: 8px;
padding: 0.65rem 0.85rem;
margin-bottom: 1rem;
font-size: 0.9rem;
border: 1px solid var(--border);
}
.status-banner.ok {
border-color: #15803d;
background: rgba(34, 197, 94, 0.12);
}
.status-banner.degraded {
border-color: #b45309;
background: rgba(245, 158, 11, 0.12);
}
.status-banner.err {
border-color: #b91c1c;
background: rgba(239, 68, 68, 0.12);
}
.stats-dl {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.25rem 1rem;
margin: 0;
font-size: 0.9rem;
}
.stats-dl dt {
margin: 0;
color: var(--muted);
}
.stats-dl dd {
margin: 0;
}
button.btn-secondary,
a.btn-secondary {
background: transparent;
color: var(--accent);
border-color: var(--accent);
text-decoration: none;
display: inline-block;
margin-top: 0;
margin-right: 0.35rem;
padding: 0.35rem 0.65rem;
font-size: 0.85rem;
}
button.btn-small {
margin-top: 0;
padding: 0.3rem 0.55rem;
font-size: 0.8rem;
}
/* Таблица кластеров: колонка «Имя» 40 % ширины таблицы (без width:1%, из‑за него в UI казалось «1 %») */
#tbl-clusters {
table-layout: fixed;
width: 90%;
}
#tbl-clusters th.col-cluster-name,
#tbl-clusters td.col-cluster-name {
width: 40%;
min-width: 0;
text-align: left;
vertical-align: middle;
overflow-wrap: break-word;
word-break: break-word;
}
/* Остальные колонки — компактно; содержимое по центру */
#tbl-clusters th.col-kind,
#tbl-clusters td.col-kind,
#tbl-clusters th.col-kubeconfig,
#tbl-clusters td.col-kubeconfig,
#tbl-clusters th.col-workers,
#tbl-clusters td.col-workers,
#tbl-clusters th.col-state,
#tbl-clusters td.col-state {
padding-left: 0.5rem;
padding-right: 0.5rem;
text-align: center;
vertical-align: middle;
white-space: nowrap;
}
#tbl-clusters th.col-version,
#tbl-clusters td.col-version {
padding-left: 0.5rem;
padding-right: 0.5rem;
text-align: center;
vertical-align: middle;
}
#tbl-clusters th.col-version {
white-space: nowrap;
}
#tbl-clusters td.col-version {
white-space: normal;
word-break: break-word;
}
/* Колонка «Действия»: доля от оставшихся 50 %, иконки в ряд */
#tbl-clusters th.col-actions,
#tbl-clusters td.actions {
padding: 0.3rem 0.25rem;
text-align: center;
vertical-align: middle;
}
#tbl-clusters td.actions {
white-space: nowrap;
}
.actions-toolbar {
display: inline-flex;
flex-wrap: nowrap;
align-items: center;
gap: 0.12rem;
}
/* Обёртка иконки; текст подсказки — в #action-tooltip (JS, fixed), иначе режется overflow таблицы */
.icon-tooltip-host {
position: relative;
display: inline-flex;
vertical-align: middle;
}
/* Плавающая подсказка над/под иконкой (полный текст, переносы строк) */
.action-tooltip-floating {
position: fixed;
z-index: 400;
left: 0;
top: 0;
max-width: min(22rem, calc(100vw - 20px));
max-height: min(70vh, 22rem);
overflow-y: auto;
padding: 0.55rem 0.7rem;
box-sizing: border-box;
font-size: 0.8rem;
font-weight: 500;
line-height: 1.45;
text-align: left;
white-space: normal;
overflow-wrap: break-word;
word-break: break-word;
hyphens: auto;
color: var(--fg);
background: var(--card);
border: 1px solid var(--border);
border-radius: 8px;
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.35);
pointer-events: none;
}
.action-tooltip-floating.hidden {
display: none;
}
.icon-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 1.95rem;
height: 1.95rem;
padding: 0;
margin: 0;
border: 1px solid var(--border);
border-radius: 6px;
background: rgba(0, 0, 0, 0.15);
color: var(--fg);
cursor: pointer;
transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.icon-btn:hover:not(:disabled) {
background: rgba(59, 130, 246, 0.2);
border-color: var(--accent);
color: var(--accent);
}
.icon-btn:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.icon-btn:disabled {
opacity: 0.4;
cursor: not-allowed;
}
.icon-btn svg {
width: 1.05rem;
height: 1.05rem;
flex-shrink: 0;
}
.icon-btn--secondary {
background: transparent;
}
.icon-btn--danger {
color: #f87171;
border-color: rgba(185, 28, 28, 0.5);
background: rgba(185, 28, 28, 0.08);
}
.icon-btn--danger:hover:not(:disabled) {
color: #fca5a5;
border-color: #ef4444;
background: rgba(239, 68, 68, 0.14);
}
html[data-theme="light"] .icon-btn {
background: rgba(59, 130, 246, 0.08);
}
html[data-theme="light"] .icon-btn--danger {
color: #b91c1c;
}
/* Модальное окно «Состояние кластера» */
.modal-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.55);
display: flex;
align-items: center;
justify-content: center;
padding: 1.25rem 1rem;
z-index: 100;
overflow-y: auto;
}
.modal-overlay.hidden {
display: none;
}
/* Поверх модалки «Состояние» (z-index 100), если когда-либо понадобится стек */
.confirm-modal-overlay {
z-index: 150;
}
/* Информация после сохранения конфига на странице редактирования кластера */
.cluster-edit-save-modal-overlay {
z-index: 160;
}
.modal-box--cluster-edit-save {
max-width: min(34rem, 100%);
text-align: left;
}
.cluster-edit-save-modal-title {
margin: 0 0 0.65rem;
font-size: 1.05rem;
text-align: center;
}
.cluster-edit-save-modal-body {
margin: 0;
font-size: 0.92rem;
line-height: 1.55;
}
.cluster-edit-save-modal-body p {
margin: 0 0 0.65rem;
}
.cluster-edit-save-modal-body p:last-child {
margin-bottom: 0;
}
.cluster-edit-save-modal-body ul {
margin: 0.35rem 0 0.85rem 1.15rem;
padding: 0;
list-style: disc;
}
.cluster-edit-save-modal-body li {
margin-bottom: 0.45rem;
}
.cluster-edit-save-modal-body li:last-child {
margin-bottom: 0;
}
.cluster-edit-save-modal-body code {
font-size: 0.86em;
word-break: break-word;
}
.cluster-edit-save-modal-body .cluster-edit-save-modal-lead {
margin-top: 0;
font-weight: 500;
color: var(--text);
}
/* Журнал развёртывания: поверх шапки и выпадающего меню API (до z-index 160); ниже полноэкранного спиннера (9998) */
.provision-log-modal-overlay {
z-index: 500;
}
.modal-box--provision-log .provision-log-body {
max-height: min(70vh, 32rem);
overflow: auto;
margin: 0.35rem 0 0;
padding: 0.65rem 0.75rem;
font-size: 0.78rem;
line-height: 1.45;
white-space: pre-wrap;
word-break: break-word;
border-radius: 8px;
border: 1px solid var(--border);
background: rgba(0, 0, 0, 0.2);
}
html[data-theme="light"] .modal-box--provision-log .provision-log-body {
background: rgba(0, 0, 0, 0.04);
}
.modal-box--confirm {
max-width: 24rem;
text-align: center;
}
.confirm-modal-title {
margin: 0 0 0.5rem;
font-size: 1.05rem;
text-align: center;
}
.confirm-modal-message {
margin: 0 0 0.25rem;
white-space: pre-wrap;
text-align: center;
}
.confirm-modal-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: 0.65rem 0.85rem;
margin-top: 1.15rem;
}
.confirm-modal-actions button {
margin-top: 0;
}
.modal-box {
background: var(--card);
border: 1px solid var(--border);
border-radius: 10px;
max-width: 52rem;
width: 100%;
max-height: calc(100vh - 2.5rem);
max-height: calc(100dvh - 2.5rem);
overflow-y: auto;
padding: 1rem 1.15rem;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
margin: auto;
}
.modal-box h3 {
margin: 0 0 0.75rem;
font-size: 1.05rem;
}
.modal-box pre {
max-height: 40vh;
margin: 0.5rem 0 1rem;
}
.modal-close {
flex-shrink: 0;
margin-top: 0;
}
button.btn-danger,
a.btn-danger {
background: transparent;
color: #f87171;
border-color: #b91c1c;
}
html[data-theme="light"] button.btn-danger,
html[data-theme="light"] a.btn-danger {
color: #b91c1c;
}
button.btn-danger:hover {
filter: brightness(1.12);
}
/* Хлебные крошки на странице документации — ширина как у .app-main (с дашбордом). */
.doc-breadcrumbs {
max-width: none;
width: 100%;
margin: 0 0 0.65rem;
padding: 0;
box-sizing: border-box;
}
.doc-breadcrumbs__list {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.35rem 0.15rem;
margin: 0;
padding: 0;
list-style: none;
font-size: 0.8125rem;
}
.doc-breadcrumbs__item {
display: inline-flex;
align-items: center;
gap: 0.35rem;
}
.doc-breadcrumbs__item:not(:last-child)::after {
content: "";
opacity: 0.45;
font-weight: 500;
margin-left: 0.2rem;
}
.doc-breadcrumbs__link {
color: var(--accent);
text-decoration: none;
}
.doc-breadcrumbs__link:hover {
text-decoration: underline;
text-underline-offset: 2px;
}
.doc-breadcrumbs__item--current {
color: var(--muted);
font-weight: 600;
max-width: 100%;
word-break: break-word;
}
/* Страница «Документация»: Markdown → карточки; ширина блока = ширина main (как card на дашборде). */
.readme-doc-shell {
max-width: none;
width: 100%;
margin: 0;
box-sizing: border-box;
}
.readme-doc-loading {
margin: 0 0 0.75rem;
font-size: 0.9rem;
}
.readme-doc-page {
width: 100%;
}
.readme-doc-page-inner {
width: 100%;
}
.readme-doc-root {
display: flex;
flex-direction: column;
gap: 1rem;
}
.readme-section-card {
margin: 0;
}
/* Заголовок секции (h2) и содержимое — в одной карточке: без лишнего зазора сверху у первого заголовка */
.readme-section-card.markdown-body > h1:first-child,
.readme-section-card.markdown-body > h2:first-child {
margin-top: 0;
}
.readme-section-card.markdown-body {
font-size: 0.95rem;
line-height: 1.55;
}
.readme-section-card.markdown-body h1,
.readme-section-card.markdown-body h2,
.readme-section-card.markdown-body h3,
.readme-section-card.markdown-body h4 {
margin: 1.25rem 0 0.5rem;
line-height: 1.25;
font-weight: 650;
}
.readme-section-card.markdown-body h1 {
font-size: 1.45rem;
border-bottom: 1px solid var(--border);
padding-bottom: 0.35rem;
}
.readme-section-card.markdown-body h2 {
font-size: 1.2rem;
border-bottom: 1px solid var(--border);
padding-bottom: 0.25rem;
}
.readme-section-card.markdown-body h3 {
font-size: 1.05rem;
}
.readme-section-card.markdown-body p {
margin: 0.5rem 0;
}
.readme-section-card.markdown-body ul,
.readme-section-card.markdown-body ol {
margin: 0.5rem 0;
padding-left: 1.35rem;
}
.readme-section-card.markdown-body li {
margin: 0.2rem 0;
}
.readme-section-card.markdown-body a {
color: var(--accent);
text-decoration: underline;
text-underline-offset: 2px;
}
.readme-section-card.markdown-body a:hover {
filter: brightness(1.15);
}
.readme-section-card.markdown-body code {
font-size: 0.88em;
padding: 0.12em 0.35em;
border-radius: 4px;
background: rgba(0, 0, 0, 0.22);
border: 1px solid var(--border);
}
.readme-section-card.markdown-body pre {
margin: 0.65rem 0;
padding: 0.65rem 0.85rem;
overflow-x: auto;
border-radius: 8px;
border: 1px solid var(--border);
background: rgba(0, 0, 0, 0.25);
font-size: 0.82rem;
line-height: 1.4;
}
.readme-section-card.markdown-body pre code {
padding: 0;
border: none;
background: transparent;
font-size: inherit;
}
.readme-section-card.markdown-body blockquote {
margin: 0.65rem 0;
padding: 0.35rem 0.75rem;
border-left: 4px solid var(--accent);
background: rgba(59, 130, 246, 0.08);
color: var(--muted);
}
.readme-section-card.markdown-body table {
width: 100%;
border-collapse: collapse;
margin: 0.75rem 0;
font-size: 0.88rem;
}
.readme-section-card.markdown-body th,
.readme-section-card.markdown-body td {
border: 1px solid var(--border);
padding: 0.4rem 0.55rem;
text-align: left;
}
.readme-section-card.markdown-body th {
background: rgba(0, 0, 0, 0.15);
font-weight: 600;
}
.readme-section-card.markdown-body hr {
border: none;
border-top: 1px solid var(--border);
margin: 1.25rem 0;
}
html[data-theme="light"] .readme-section-card.markdown-body code {
background: rgba(59, 130, 246, 0.1);
}
html[data-theme="light"] .readme-section-card.markdown-body pre {
background: rgba(59, 130, 246, 0.06);
}
html[data-theme="light"] .readme-section-card.markdown-body th {
background: rgba(59, 130, 246, 0.14);
}
/* Страница кластера: /cluster/<имя> — сводка, kubectl, действия */
.cluster-detail-breadcrumb {
margin: 0 0 1rem;
font-size: 0.9rem;
}
.cluster-detail-breadcrumb a {
color: var(--accent);
text-decoration: none;
}
.cluster-detail-breadcrumb a:hover {
text-decoration: underline;
}
/* Ссылка на страницу кластера в таблице: контраст в светлой и тёмной теме */
.cluster-name-link {
text-decoration: none;
font-weight: 600;
border-bottom: 1px solid transparent;
}
html[data-theme="light"] .cluster-name-link {
color: #0369a1;
}
html[data-theme="light"] .cluster-name-link:hover {
color: #0c4a6e;
border-bottom-color: #0369a1;
}
html[data-theme="light"] .cluster-name-link .cluster-name {
color: inherit;
}
html[data-theme="dark"] .cluster-name-link {
color: #7dd3fc;
}
html[data-theme="dark"] .cluster-name-link:hover {
color: #e0f2fe;
border-bottom-color: #38bdf8;
}
html[data-theme="dark"] .cluster-name-link .cluster-name {
color: inherit;
}
/* Страница кластера: отступы между карточками */
body.cluster-detail-page .app-main > .card {
margin-bottom: 1.35rem;
}
body.cluster-detail-page .app-main > .card:last-child {
margin-bottom: 0;
}
/* Шапка страницы кластера: слева заголовок и кнопки, справа мета столбиком */
.cluster-detail-hero-layout {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
justify-content: space-between;
gap: 1rem 1.75rem;
}
.cluster-detail-hero-left {
flex: 1 1 14rem;
min-width: 0;
}
.cluster-detail-hero-meta {
flex: 0 0 auto;
align-self: flex-start;
}
.cluster-detail-hero-card .page-title {
margin-bottom: 0.5rem;
}
.cluster-detail-meta {
min-width: 14rem;
max-width: 28rem;
}
/* Компактная карточка сводки (kind, kubeconfig, состояние, версия, workers) */
.cluster-detail-meta-card {
border-radius: 12px;
border: 1px solid var(--border);
background: linear-gradient(
155deg,
rgba(59, 130, 246, 0.09) 0%,
rgba(15, 23, 42, 0.35) 48%,
rgba(15, 23, 42, 0.2) 100%
);
padding: 0.65rem 0.75rem 0.7rem;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
}
html[data-theme="light"] .cluster-detail-meta-card {
background: linear-gradient(
155deg,
rgba(59, 130, 246, 0.12) 0%,
rgba(255, 255, 255, 0.95) 55%,
rgba(241, 245, 249, 0.9) 100%
);
box-shadow: 0 4px 18px rgba(15, 23, 42, 0.08);
}
.cluster-detail-meta-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 0.5rem 0.55rem;
}
@media (max-width: 720px) {
.cluster-detail-meta-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 400px) {
.cluster-detail-meta-grid {
grid-template-columns: 1fr;
}
}
.cluster-meta-tile {
display: flex;
flex-direction: column;
gap: 0.2rem;
padding: 0.35rem 0.4rem;
border-radius: 8px;
background: rgba(0, 0, 0, 0.14);
border: 1px solid rgba(255, 255, 255, 0.06);
min-width: 0;
}
html[data-theme="light"] .cluster-meta-tile {
background: rgba(255, 255, 255, 0.65);
border-color: rgba(59, 130, 246, 0.15);
}
.cluster-meta-tile__label {
font-size: 0.65rem;
font-weight: 650;
text-transform: uppercase;
letter-spacing: 0.06em;
line-height: 1.2;
}
.cluster-meta-tile__value {
font-size: 0.88rem;
font-weight: 600;
line-height: 1.25;
min-height: 1.25rem;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.2rem;
}
.cluster-meta-tile--wide {
grid-column: 1 / -1;
}
.cluster-meta-badge {
font-size: 0.78rem !important;
padding: 0.12rem 0.45rem !important;
}
.cluster-meta-badge--muted {
background: transparent !important;
border: 1px dashed var(--border) !important;
color: var(--muted) !important;
font-weight: 500 !important;
}
.cluster-meta-version-tag {
font-size: 0.78rem;
font-weight: 600;
padding: 0.1rem 0.35rem;
border-radius: 6px;
background: rgba(0, 0, 0, 0.2);
border: 1px solid var(--border);
}
html[data-theme="light"] .cluster-meta-version-tag {
background: rgba(59, 130, 246, 0.08);
}
.cluster-meta-workers {
font-variant-numeric: tabular-nums;
font-size: 0.95rem;
}
/* Обёртка кнопок действий под заголовком кластера */
.cluster-detail-actions-card {
display: inline-flex;
align-items: center;
padding: 0.4rem 0.45rem;
margin-bottom: 0.35rem;
border-radius: 10px;
border: 1px solid var(--border);
background: rgba(0, 0, 0, 0.1);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
}
html[data-theme="light"] .cluster-detail-actions-card {
background: rgba(15, 23, 42, 0.03);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8);
}
.cluster-detail-actions-card .cluster-detail-toolbar {
margin: 0;
}
.cluster-k8s-scope-hint {
margin: 0 0 0.85rem;
font-size: 0.86rem;
line-height: 1.45;
max-width: 48rem;
}
.cluster-k8s-scope-hint code {
font-size: 0.8em;
}
.cluster-detail-meta__column {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 0.35rem 0;
text-align: right;
}
.cluster-detail-meta__line {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.35rem 0.65rem;
align-items: baseline;
font-size: 0.88rem;
width: 100%;
max-width: 22rem;
}
.cluster-detail-meta__label {
justify-self: end;
white-space: nowrap;
}
.cluster-detail-meta__value {
justify-self: start;
text-align: left;
min-width: 0;
}
.cluster-detail-hero-main {
flex: 1 1 12rem;
min-width: 0;
}
.cluster-detail-hero-actions {
flex: 0 0 auto;
align-self: flex-end;
}
.cluster-detail-hero-actions .actions-toolbar {
justify-content: flex-end;
flex-wrap: wrap;
gap: 0.35rem;
max-width: 22rem;
}
@media (max-width: 640px) {
.cluster-detail-hero-layout {
flex-direction: column;
align-items: stretch;
}
.cluster-detail-hero-meta {
align-self: stretch;
}
.cluster-detail-meta {
max-width: none;
}
.cluster-detail-meta__column {
align-items: flex-start;
text-align: left;
}
.cluster-detail-meta__line {
grid-template-columns: 6.5rem 1fr;
max-width: none;
}
.cluster-detail-meta__label {
justify-self: start;
}
.cluster-detail-meta__value {
justify-self: start;
}
.cluster-detail-hero-actions {
align-self: stretch;
}
.cluster-detail-hero-actions .actions-toolbar {
justify-content: flex-start;
max-width: none;
}
}
.cluster-detail-section-title {
font-size: 1.05rem;
margin: 0 0 0.65rem;
}
.cluster-detail-meta__row {
display: flex;
flex-wrap: wrap;
gap: 0.5rem 1.25rem;
margin-top: 0.5rem;
}
.cluster-detail-meta__item {
font-size: 0.88rem;
}
.cluster-detail-toolbar {
margin: 0;
}
.cluster-kube-hint {
margin: 0;
padding: 0.5rem 0.65rem;
border-radius: 8px;
border: 1px solid var(--border);
background: rgba(234, 179, 8, 0.12);
}
/* Ожидаемое состояние: узлы остановлены — не предупреждение, а подсказка */
.cluster-kube-hint.cluster-kube-hint--info {
background: rgba(59, 130, 246, 0.12);
border-color: rgba(59, 130, 246, 0.35);
}
html[data-theme="light"] .cluster-kube-hint.cluster-kube-hint--info {
background: rgba(59, 130, 246, 0.08);
border-color: rgba(37, 99, 235, 0.35);
}
/* Вводная карточка kubectl + отдельная карточка на каждый ресурс (как в шаблоне cluster_detail) */
.cluster-k8s-intro-card .cluster-k8s-scope-hint {
margin: 0 0 0.75rem;
}
.cluster-k8s-resource-card .cluster-detail-section-title {
margin: 0 0 0.55rem;
font-size: 1.02rem;
}
/* Сетка карточек узлов на странице кластера: не более 3 карточек в ряд */
.cluster-page-node-cards--wide.cluster-nodes-resources__cards-row {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 0.75rem;
flex-wrap: wrap;
overflow-x: visible;
width: 100%;
}
@media (max-width: 52rem) {
.cluster-page-node-cards--wide.cluster-nodes-resources__cards-row {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 32rem) {
.cluster-page-node-cards--wide.cluster-nodes-resources__cards-row {
grid-template-columns: 1fr;
}
}
.cluster-page-node-cards--wide .cluster-node-res-card {
width: auto;
min-width: 0;
flex: none;
}
/* Таблицы Kubernetes (kubectl -o json) */
.cluster-k8s-root {
min-height: 1.5rem;
}
.cluster-k8s-msg {
margin: 0;
font-size: 0.85rem;
line-height: 1.45;
}
.cluster-k8s-table-scroll {
width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
border-radius: 8px;
border: 1px solid var(--border);
background: rgba(0, 0, 0, 0.12);
}
html[data-theme="light"] .cluster-k8s-table-scroll {
background: rgba(15, 23, 42, 0.04);
}
.cluster-k8s-table {
width: 100%;
min-width: 36rem;
border-collapse: collapse;
font-size: 0.8rem;
}
.cluster-k8s-table th,
.cluster-k8s-table td {
padding: 0.4rem 0.55rem;
text-align: left;
border-bottom: 1px solid var(--border);
vertical-align: middle;
}
.cluster-k8s-table th {
font-weight: 650;
color: var(--muted);
white-space: nowrap;
background: rgba(0, 0, 0, 0.18);
}
html[data-theme="light"] .cluster-k8s-table th {
background: rgba(59, 130, 246, 0.1);
}
.cluster-k8s-table tbody tr:last-child td {
border-bottom: none;
}
.cluster-k8s-table td:last-child {
width: 1%;
white-space: nowrap;
}
.cluster-k8s-table .icon-tooltip-host {
display: inline-flex;
vertical-align: middle;
}
.btn-k8s-restart {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.25rem 0.5rem;
font-size: 0.78rem;
}
.btn-k8s-restart svg {
width: 1rem;
height: 1rem;
flex-shrink: 0;
}
/* Рестарт пода: только иконка; подсказка — #action-tooltip (.icon-tooltip-host) */
.btn-k8s-restart--solo {
width: 2rem;
height: 2rem;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 8px;
}
.btn-k8s-restart--solo svg {
width: 1.05rem;
height: 1.05rem;
}
.cluster-kube-pre {
max-height: 16rem;
overflow: auto;
margin: 0;
padding: 0.5rem 0.65rem;
font-size: 0.78rem;
line-height: 1.35;
border-radius: 8px;
border: 1px solid var(--border);
background: rgba(0, 0, 0, 0.2);
}
html[data-theme="light"] .cluster-kube-pre {
background: rgba(15, 23, 42, 0.04);
}
/* Полноэкранный спиннер первой загрузки главной панели */
body.dashboard-home-loading {
overflow: hidden;
}
/* Полноэкранный спиннер первой загрузки страницы кластера */
body.cluster-page-loading {
overflow: hidden;
}
.page-loading-overlay {
position: fixed;
inset: 0;
z-index: 9998;
display: flex;
align-items: center;
justify-content: center;
}
.page-loading-overlay.hidden {
display: none;
pointer-events: none;
}
/* Старт/стоп кластера: тот же полноэкранный паттерн, z-index ниже полноэкранных ошибок при необходимости */
.cluster-lifecycle-job-overlay {
z-index: 9996;
}
body.cluster-lifecycle-job-busy {
overflow: hidden;
}
.page-loading-backdrop {
position: absolute;
inset: 0;
background: rgba(15, 23, 42, 0.52);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
html[data-theme="light"] .page-loading-backdrop {
background: rgba(241, 245, 249, 0.72);
}
.page-loading-center {
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
padding: 1.35rem 1.75rem;
border-radius: 12px;
border: 1px solid var(--border);
background: var(--card);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
}
html[data-theme="light"] .page-loading-center {
box-shadow: 0 12px 40px rgba(15, 23, 42, 0.12);
}
.page-loading-spinner {
width: 2.5rem;
height: 2.5rem;
border-width: 4px;
}
.page-loading-label {
font-size: 0.92rem;
color: var(--muted);
text-align: center;
max-width: 18rem;
line-height: 1.4;
}
/* Редактирование кластера (cluster_edit.html).
Автор: Сергей Антропов — https://devops.org.ru */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.cluster-edit-hint {
margin: 0 0 1rem;
font-size: 0.92rem;
line-height: 1.45;
}
.cluster-edit-mode-fieldset {
border: none;
margin: 0 0 1.25rem;
padding: 0;
}
.cluster-edit-mode-legend {
font-size: 0.78rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--muted);
margin: 0 0 0.65rem;
padding: 0;
}
/* Сегментный переключатель «Простой / Расширенный»: одна строка, равная высота */
.cluster-edit-segmented {
display: flex;
flex-wrap: nowrap;
align-items: stretch;
width: 100%;
max-width: 42rem;
padding: 4px;
border-radius: 14px;
border: 1px solid var(--border);
background: rgba(0, 0, 0, 0.18);
gap: 4px;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.12);
}
html[data-theme="light"] .cluster-edit-segmented {
background: rgba(15, 23, 42, 0.06);
box-shadow: inset 0 1px 2px rgba(15, 23, 42, 0.06);
}
.cluster-edit-segment-item {
position: relative;
display: flex;
flex: 1 1 0;
min-width: 0;
min-height: 5.35rem;
}
.cluster-edit-segment-native {
position: absolute;
opacity: 0;
width: 1px;
height: 1px;
margin: 0;
pointer-events: none;
}
.cluster-edit-segment-label {
display: flex;
flex: 1;
flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: 0;
margin: 0;
padding: 0.75rem 1.05rem;
border-radius: 10px;
cursor: pointer;
border: 1px solid transparent;
box-sizing: border-box;
transition:
background 0.18s ease,
color 0.18s ease,
border-color 0.18s ease,
box-shadow 0.18s ease;
color: var(--muted);
font-weight: 500;
line-height: 1.25;
min-height: 100%;
}
.cluster-edit-segment-title {
font-size: 0.98rem;
color: inherit;
font-weight: 600;
}
.cluster-edit-segment-sub-wrap {
display: flex;
flex-direction: column;
gap: 0.12rem;
margin-top: 0.35rem;
}
.cluster-edit-segment-sub {
font-size: 0.76rem;
font-weight: 400;
opacity: 0.9;
line-height: 1.32;
}
.cluster-edit-segment-native:focus-visible + .cluster-edit-segment-label {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.cluster-edit-segment-native:checked + .cluster-edit-segment-label {
background: var(--accent);
color: #f8fafc;
border-color: var(--accent);
box-shadow: 0 2px 14px rgba(59, 130, 246, 0.35);
}
.cluster-edit-segment-native:checked + .cluster-edit-segment-label .cluster-edit-segment-sub {
color: inherit;
opacity: 0.92;
}
.cluster-edit-mode-hint {
margin: 0.75rem 0 0;
font-size: 0.88rem;
line-height: 1.45;
max-width: 40rem;
}
.cluster-edit-advanced-wrap {
margin-bottom: 1rem;
}
.cluster-edit-advanced-intro {
margin: 0 0 1.15rem;
padding: 0.75rem 1rem;
border-radius: 10px;
border: 1px solid var(--border);
background: rgba(59, 130, 246, 0.08);
}
html[data-theme="light"] .cluster-edit-advanced-intro {
background: rgba(59, 130, 246, 0.06);
}
.cluster-edit-advanced-intro-text {
margin: 0;
font-size: 0.88rem;
line-height: 1.5;
color: var(--fg);
}
.cluster-edit-panels {
display: flex;
flex-direction: column;
gap: 1rem;
margin-bottom: 1.15rem;
}
.cluster-edit-panel {
border-radius: 12px;
border: 1px solid var(--border);
background: var(--card);
overflow: hidden;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.04) inset;
}
html[data-theme="light"] .cluster-edit-panel {
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06);
}
.cluster-edit-panel-head {
padding: 0.85rem 1.1rem 0.75rem;
border-bottom: 1px solid var(--border);
background: rgba(0, 0, 0, 0.14);
}
html[data-theme="light"] .cluster-edit-panel-head {
background: rgba(15, 23, 42, 0.04);
}
.cluster-edit-panel-title {
margin: 0 0 0.35rem;
font-size: 1rem;
font-weight: 600;
letter-spacing: -0.01em;
}
.cluster-edit-panel-desc {
margin: 0;
font-size: 0.82rem;
line-height: 1.45;
}
.cluster-edit-panel-body {
padding: 1rem 1.1rem 1.05rem;
}
.cluster-edit-panel-grid {
display: grid;
grid-template-columns: 1fr;
gap: 0.85rem 1.25rem;
}
@media (min-width: 640px) {
.cluster-edit-panel-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
.cluster-edit-panel-grid--tight {
gap: 0.65rem 1rem;
}
.cluster-edit-panel-span {
grid-column: 1 / -1;
}
.cluster-edit-check-label {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
gap: 0.5rem;
font-size: 0.9rem;
line-height: 1.35;
cursor: pointer;
text-align: left;
}
.cluster-edit-check-label input[type="checkbox"] {
margin: 0;
flex-shrink: 0;
}
.cluster-edit-check-label--card {
display: inline-flex;
align-items: center;
box-sizing: border-box;
padding: 0.55rem 0.75rem;
border-radius: 8px;
border: 1px solid var(--border);
background: rgba(0, 0, 0, 0.12);
max-width: 100%;
}
/* Один ряд: краткий заголовок — пояснение (сжимается с многоточием при нехватке места) */
.cluster-edit-check-inline {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-items: center;
gap: 0.35rem;
min-width: 0;
flex: 1;
overflow: hidden;
}
.cluster-edit-check-title {
flex: 0 1 auto;
min-width: 0;
max-width: min(22rem, 58%);
font-weight: 600;
margin: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.cluster-edit-check-sep {
flex-shrink: 0;
padding: 0 0.05rem;
user-select: none;
}
.cluster-edit-check-hint {
flex: 1;
min-width: 0;
margin: 0;
font-size: 0.86em;
line-height: 1.35;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.cluster-edit-check-hint a {
white-space: nowrap;
}
html[data-theme="light"] .cluster-edit-check-label--card {
background: rgba(15, 23, 42, 0.03);
}
.cluster-edit-port-card {
margin-top: 0.75rem;
padding: 0.85rem 0.9rem 0.95rem;
border-radius: 10px;
border: 1px dashed var(--border);
background: rgba(0, 0, 0, 0.1);
}
html[data-theme="light"] .cluster-edit-port-card {
background: rgba(15, 23, 42, 0.03);
}
.create-cluster-card .field-hint {
display: block;
margin-top: 0.3rem;
font-size: 0.76rem;
line-height: 1.35;
}
.cluster-edit-kubeadm-textarea {
width: 100%;
min-height: 7rem;
resize: vertical;
font-size: 0.82rem;
line-height: 1.35;
}
.cluster-edit-yaml-preview-card {
border-radius: 10px;
border: 1px solid var(--border);
background: rgba(0, 0, 0, 0.2);
overflow: hidden;
}
html[data-theme="light"] .cluster-edit-yaml-preview-card {
background: rgba(15, 23, 42, 0.04);
}
.cluster-edit-yaml-preview-head {
display: flex;
flex-wrap: wrap;
align-items: baseline;
justify-content: space-between;
gap: 0.35rem 0.75rem;
padding: 0.5rem 0.75rem;
border-bottom: 1px solid var(--border);
background: rgba(0, 0, 0, 0.12);
}
html[data-theme="light"] .cluster-edit-yaml-preview-head {
background: rgba(15, 23, 42, 0.05);
}
.cluster-edit-yaml-preview-title {
font-size: 0.82rem;
font-weight: 600;
}
.cluster-edit-yaml-preview-note {
font-size: 0.75rem;
}
.cluster-edit-yaml-preview-pre {
margin: 0;
padding: 0.75rem 1rem;
max-height: 22rem;
overflow: auto;
font-size: 0.78rem;
line-height: 1.4;
white-space: pre-wrap;
word-break: break-word;
}
.cluster-edit-actions {
gap: 0.75rem;
align-items: center;
flex-wrap: wrap;
}
.cluster-edit-cancel-link {
text-decoration: none;
display: inline-flex;
align-items: center;
justify-content: center;
}