Files
KindClustersDashboard/app/static/style.css
T
Sergey Antropoff c49555b3b9 docs: скриншоты UI (светлая/тёмная тема) в app/docs и README
- app/docs/screenshots.md и каталог app/docs/images/*.png
- раздача /static/docs-images/* из FastAPI; documentation.js переписывает src картинок
- стили .markdown-body img; строка в api_routes.md; превью в README
2026-04-05 01:18:22 +03:00

5093 lines
125 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;
/* Текст на кнопках/ссылках с фоном --accent (тёмная и светлая тема) */
--on-accent: #ffffff;
/* Текстовые ссылки: та же синяя гамма, что и акценты UI (без отдельного цвета :visited) */
--link: #93c5fd;
--link-hover: #e0f2fe;
}
/* Светлая тема: основной текст и акценты в синей гамме (как тёмная), без «чистого» чёрного */
html[data-theme="light"] {
color-scheme: light;
--bg: #eef2fb;
--fg: #172c46;
--muted: #5a6f8f;
--card: #ffffff;
--border: #b8c9e8;
--accent: #3b82f6;
--on-accent: #ffffff;
--link: #2563eb;
--link-hover: #1e3a8a;
}
body {
margin: 0;
padding: 0;
background: var(--bg);
color: var(--fg);
line-height: 1.45;
}
body.modal-open {
overflow: hidden;
}
/* Обычные ссылки <a href>: единый вид до и после перехода (перебиваем системный :visited). :where — низкая специфичность. */
a:where([href]) {
color: var(--link);
text-decoration: underline;
/* Fallback без color-mix; поверх — смешивание с --accent */
text-decoration-color: rgba(59, 130, 246, 0.4);
text-decoration-color: color-mix(in srgb, var(--accent) 42%, transparent);
text-underline-offset: 0.22em;
text-decoration-thickness: max(1px, 0.065em);
text-decoration-skip-ink: auto;
transition: color 0.15s ease, text-decoration-color 0.15s ease;
}
a:where([href]):visited {
color: var(--link);
text-decoration-color: rgba(59, 130, 246, 0.4);
text-decoration-color: color-mix(in srgb, var(--accent) 42%, transparent);
}
a:where([href]):hover {
color: var(--link-hover);
text-decoration-color: rgba(59, 130, 246, 0.65);
text-decoration-color: color-mix(in srgb, var(--accent) 72%, transparent);
}
a:where([href]):visited:hover {
color: var(--link-hover);
text-decoration-color: rgba(59, 130, 246, 0.65);
text-decoration-color: color-mix(in srgb, var(--accent) 72%, transparent);
}
a:where([href]):focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
border-radius: 2px;
}
/* Пропуск к основному содержимому (a11y) */
.skip-link {
position: absolute;
left: -9999px;
top: 0.5rem;
z-index: 200;
padding: 0.5rem 1rem;
background: var(--accent);
color: var(--on-accent);
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;
}
/* Тёмная тема: название в шапке — чисто белый (остальной текст остаётся --fg) */
html:not([data-theme="light"]) .nav-brand-link .nav-title {
color: #ffffff;
}
html:not([data-theme="light"]) .nav-brand-link:hover .nav-title {
color: var(--accent);
}
.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;
}
/* Кнопка «гамбургер» (видна при ширине < 920px; синхронно с nav-mobile.js) */
.nav-menu-toggle {
display: none;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: 2.85rem;
height: 2.85rem;
margin: 0;
padding: 0;
border: 1px solid rgba(59, 130, 246, 0.35);
border-radius: 14px;
background: linear-gradient(145deg, rgba(59, 130, 246, 0.22), rgba(15, 23, 42, 0.35));
color: var(--fg);
cursor: pointer;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.2);
transition:
background 0.22s ease,
border-color 0.22s ease,
color 0.22s ease,
box-shadow 0.22s ease,
transform 0.18s ease;
}
html[data-theme="light"] .nav-menu-toggle {
background: linear-gradient(145deg, rgba(59, 130, 246, 0.2), rgba(255, 255, 255, 0.95));
border-color: rgba(59, 130, 246, 0.4);
color: var(--accent);
box-shadow: 0 2px 14px rgba(59, 130, 246, 0.18);
}
.nav-menu-toggle:hover {
border-color: var(--accent);
background: linear-gradient(145deg, rgba(59, 130, 246, 0.32), rgba(59, 130, 246, 0.12));
color: var(--accent);
box-shadow: 0 4px 18px rgba(59, 130, 246, 0.28);
}
html[data-theme="light"] .nav-menu-toggle:hover {
color: #1d4ed8;
}
.nav-menu-toggle:active {
transform: scale(0.96);
}
.nav-menu-toggle:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
.nav-menu-toggle__bars {
display: flex;
flex-direction: column;
justify-content: center;
gap: 5px;
width: 1.25rem;
}
.nav-menu-toggle__bar {
display: block;
height: 2.5px;
border-radius: 2px;
background: currentColor;
transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.2s ease;
}
.nav-menu-toggle--open .nav-menu-toggle__bar:nth-child(1) {
transform: translateY(7.5px) rotate(45deg);
}
.nav-menu-toggle--open .nav-menu-toggle__bar:nth-child(2) {
opacity: 0;
transform: scaleX(0);
}
.nav-menu-toggle--open .nav-menu-toggle__bar:nth-child(3) {
transform: translateY(-7.5px) rotate(-45deg);
}
@media (prefers-reduced-motion: reduce) {
.nav-menu-toggle__bar {
transition: none;
}
.nav-menu-toggle:active {
transform: none;
}
}
/* Подложка под выезжающее меню */
.nav-menu-backdrop {
position: fixed;
inset: 0;
z-index: 270;
margin: 0;
padding: 0;
border: none;
background: rgba(8, 12, 22, 0.58);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
cursor: pointer;
transition: opacity 0.28s ease, backdrop-filter 0.28s ease;
}
html[data-theme="light"] .nav-menu-backdrop {
background: rgba(15, 23, 42, 0.32);
}
/* Шапка боковой панели: только на узких экранах (см. медиазапрос) */
.nav-drawer-header {
display: none;
}
.nav-drawer-title {
font-size: 1.08rem;
font-weight: 700;
letter-spacing: -0.03em;
color: var(--fg);
}
.nav-drawer-close {
align-items: center;
justify-content: center;
width: 2.5rem;
height: 2.5rem;
margin: 0;
padding: 0;
border: none;
border-radius: 12px;
background: rgba(59, 130, 246, 0.12);
color: var(--muted);
cursor: pointer;
transition: background 0.18s ease, color 0.18s ease, transform 0.15s ease;
}
.nav-drawer-close:hover {
background: rgba(239, 68, 68, 0.15);
color: #f87171;
}
html[data-theme="light"] .nav-drawer-close:hover {
color: #b91c1c;
}
.nav-drawer-close:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.nav-drawer-close:active {
transform: scale(0.94);
}
@media (max-width: 919px) {
.top-nav-inner {
flex-wrap: nowrap;
align-items: center;
justify-content: space-between;
gap: 0.5rem 0.75rem;
padding-left: 0.85rem;
padding-right: 0.85rem;
}
.nav-brand-link {
min-width: 0;
}
.nav-title {
font-size: clamp(0.95rem, 4vw, 1.05rem);
}
.nav-menu-toggle {
display: inline-flex;
}
.nav-drawer-header {
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
gap: 0.75rem;
margin: 0 0 0.35rem;
padding-bottom: 1rem;
border-bottom: 1px solid rgba(59, 130, 246, 0.18);
}
html[data-theme="light"] .nav-drawer-header {
border-bottom-color: rgba(59, 130, 246, 0.22);
}
.nav-drawer-close {
display: inline-flex;
flex-shrink: 0;
}
/* Панель: выезд справа, скругление, градиент; API-меню без обрезки */
.top-nav-actions {
position: fixed;
top: 0;
right: 0;
bottom: 0;
z-index: 280;
width: min(21.5rem, min(92vw, 100% - 1.25rem));
max-width: 100%;
flex-direction: column;
flex-wrap: nowrap;
align-items: stretch;
justify-content: flex-start;
gap: 0.65rem;
margin: 0;
padding: max(1rem, env(safe-area-inset-top, 0px)) 1.15rem max(1.25rem, env(safe-area-inset-bottom, 0px));
padding-left: max(1.15rem, env(safe-area-inset-left, 0px));
padding-right: max(1.15rem, env(safe-area-inset-right, 0px));
overflow-x: visible;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
background: var(--card);
background: linear-gradient(
165deg,
var(--card) 0%,
color-mix(in srgb, var(--card) 88%, var(--accent) 6%) 55%,
color-mix(in srgb, var(--card) 94%, var(--bg)) 100%
);
border-left: 1px solid var(--border);
border-left: 1px solid color-mix(in srgb, var(--border) 75%, var(--accent) 25%);
border-radius: 1.35rem 0 0 1.35rem;
box-shadow:
-12px 0 40px rgba(0, 0, 0, 0.38),
-2px 0 0 rgba(59, 130, 246, 0.12) inset;
transform: translateX(108%);
visibility: hidden;
pointer-events: none;
transition: transform 0.34s cubic-bezier(0.22, 1, 0.36, 1);
}
html[data-theme="light"] .top-nav-actions {
background: #ffffff;
background: linear-gradient(165deg, #ffffff 0%, #f0f6ff 48%, #eef2fb 100%);
border-left-color: rgba(59, 130, 246, 0.28);
box-shadow:
-10px 0 36px rgba(15, 23, 42, 0.1),
-1px 0 0 rgba(59, 130, 246, 0.15) inset;
}
.top-nav-actions--open {
transform: translateX(0);
visibility: visible;
pointer-events: auto;
}
@media (prefers-reduced-motion: reduce) {
.top-nav-actions {
transition: transform 0.18s ease;
}
}
.top-nav-actions .nav-links-scroll {
flex-direction: column;
align-items: stretch;
flex-wrap: nowrap;
overflow-x: visible;
min-width: 0;
width: 100%;
padding: 0.15rem 0 0.35rem;
gap: 0.45rem;
}
.top-nav-actions .nav-link.nav-pill {
width: 100%;
justify-content: flex-start;
box-sizing: border-box;
padding: 0.72rem 1.05rem;
font-size: 0.94rem;
border-radius: 14px;
border: 1px solid rgba(59, 130, 246, 0.2);
background: rgba(0, 0, 0, 0.2);
}
html[data-theme="light"] .top-nav-actions .nav-link.nav-pill {
background: rgba(255, 255, 255, 0.85);
border-color: rgba(59, 130, 246, 0.22);
}
.top-nav-actions .nav-link.nav-pill:hover {
transform: none;
border-color: var(--accent);
background: rgba(59, 130, 246, 0.14);
}
html[data-theme="light"] .top-nav-actions .nav-link.nav-pill:hover {
background: rgba(59, 130, 246, 0.1);
}
.top-nav-actions .nav-link.nav-pill.nav-pill--active:not(.nav-pill--ext) {
border-color: rgba(59, 130, 246, 0.65);
box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.25);
}
.top-nav-actions .nav-dropdown {
width: 100%;
flex-direction: column;
align-items: stretch;
margin-top: 0.25rem;
padding-top: 0.65rem;
border-top: 1px dashed rgba(59, 130, 246, 0.22);
}
.top-nav-actions .nav-dropdown__trigger {
width: 100%;
justify-content: space-between;
padding: 0.72rem 1.05rem;
font-size: 0.94rem;
border-radius: 14px;
}
.top-nav-actions .nav-dropdown__menu {
position: static;
right: auto;
left: auto;
width: 100%;
min-width: 0;
margin-top: 0.45rem;
padding: 0.25rem 0;
border-radius: 12px;
border: 1px solid rgba(59, 130, 246, 0.15);
background: color-mix(in srgb, var(--card) 92%, transparent);
box-shadow: 0 8px 28px rgba(0, 0, 0, 0.22);
}
html[data-theme="light"] .top-nav-actions .nav-dropdown__menu {
background: rgba(255, 255, 255, 0.97);
box-shadow: 0 8px 28px rgba(15, 23, 42, 0.08);
}
.top-nav-actions .theme-toggle--nav-end {
transform: none;
width: 100%;
min-height: 2.85rem;
margin-top: auto;
padding-top: 0.85rem;
padding-bottom: 0.85rem;
justify-content: center;
border-radius: 14px;
font-size: 0.88rem;
}
}
body.nav-mobile-open {
overflow: hidden;
}
.app-main {
max-width: 72rem;
margin: 0 auto;
padding: 1.25rem;
outline: none;
}
/* Узкие экраны: меньше боковые поля, комфортный тап */
@media (max-width: 767px) {
.app-main {
padding: 1rem 0.75rem;
}
}
.app-footer {
max-width: 72rem;
margin: 0 auto;
padding: 1rem 1.25rem 2rem;
border-top: 1px solid var(--border);
font-size: 0.85rem;
}
@media (max-width: 767px) {
.app-footer {
padding-left: 0.75rem;
padding-right: 0.75rem;
padding-bottom: max(1.5rem, env(safe-area-inset-bottom, 0px));
}
}
/* Широкие мониторы: чуть шире контентная колонка */
@media (min-width: 1320px) {
.app-main,
.top-nav-inner,
.app-footer {
max-width: min(84rem, calc(100% - 2.5rem));
}
}
.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;
}
/* Отдельная карточка на панели: донаты + список кластеров (GET /stats) */
.home-resources-summary-inner {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.home-resources-summary-card .donuts-card-title {
margin-bottom: 0.5rem;
}
/* Пояснение: узлы 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 (3 в ряд); число каталогов — в сетке метрик под ними */
.stats-env-cards {
display: grid;
grid-template-columns: repeat(3, 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);
}
/* Метрики панели: по 3 карточки в ряд (карточка «Статистика» на главной с CTA «Создать кластер») */
.stats-metrics-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0.65rem;
flex: 1 1 auto;
align-content: start;
}
/* Уже чем 520px — две колонки мини-карточек, а не одна длинная колонка */
@media (max-width: 519px) {
.stats-metrics-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.5rem 0.45rem;
}
.stats-tile {
min-height: 3.85rem;
padding: 0.58rem 0.35rem;
}
.stats-tile__value {
font-size: 1.12rem;
}
.stats-tile__label {
font-size: 0.62rem;
}
}
.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);
}
/* Главная: «Перейти к созданию кластера» — размер шрифта, отступы и скругление плавно от ширины viewport */
.btn-cta-large {
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
min-width: 0;
max-width: min(22rem, 100%);
width: fit-content;
margin-top: 0;
padding: clamp(0.48rem, 0.34rem + 0.75vw, 0.95rem) clamp(0.72rem, 0.38rem + 2.35vw, 2.25rem);
font-size: clamp(0.78rem, 0.58rem + 0.95vw, 1.15rem);
font-weight: 650;
line-height: 1.2;
border-radius: clamp(8px, 0.45rem + 0.55vw, 12px);
text-decoration: none;
box-shadow: 0 clamp(2px, 0.2vw + 1px, 4px) clamp(7px, 0.35rem + 0.9vw, 14px) rgba(0, 0, 0, 0.18);
border: 1px solid transparent;
background: var(--accent);
color: var(--on-accent);
cursor: pointer;
}
a.btn-cta-large:hover {
filter: brightness(1.08);
}
/* Ссылка-кнопка: глобальные стили a[href] не перекрашивают текст и :visited */
a.btn-cta-large,
a.clusters-page-create-btn {
color: var(--on-accent);
text-decoration: none;
}
a.btn-cta-large:visited,
a.btn-cta-large:hover,
a.btn-cta-large:visited:hover,
a.clusters-page-create-btn:visited,
a.clusters-page-create-btn:hover,
a.clusters-page-create-btn:visited:hover {
color: var(--on-accent);
}
/* Сводка-денаты по узлам */
.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;
overscroll-behavior-x: contain;
scrollbar-width: thin;
}
/* Раньше переносились только от 480px; на главной/кластерах сводка «Ресурсы узлов» — с <710px сразу в несколько строк */
@media (max-width: 709px) {
.donut-grid {
flex-wrap: wrap;
justify-content: center;
overflow-x: visible;
row-gap: 1.1rem;
}
}
.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);
}
/* Страница «Кластеры»: заголовок слева, кнопка «Создать кластер» справа; по вертикали — по центру блока */
.clusters-page-hero-row {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 1rem 1.5rem;
}
.clusters-page-hero-text {
flex: 1 1 14rem;
min-width: 0;
}
.clusters-page-hero-lead {
margin: 0;
}
.clusters-page-hero-actions {
flex: 0 0 auto;
display: flex;
align-items: center;
align-self: center;
padding-top: 0;
}
@media (max-width: 520px) {
/* Остаёмся в ряд при возможности: кнопка по центру по высоте относительно заголовка, не «внизу» колонки */
.clusters-page-hero-row {
flex-direction: row;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
}
.clusters-page-hero-text {
flex: 1 1 min(100%, 16rem);
}
.clusters-page-hero-actions {
flex: 0 0 auto;
margin-left: auto;
}
.clusters-page-create-btn {
width: auto;
max-width: 100%;
justify-content: center;
box-sizing: border-box;
}
}
@media (max-width: 380px) {
.clusters-page-hero-row {
flex-direction: column;
align-items: stretch;
}
.clusters-page-hero-actions {
margin-left: 0;
}
.clusters-page-create-btn {
width: 100%;
}
}
.clusters-page-create-btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.6rem 1.35rem;
font-size: 0.95rem;
font-weight: 650;
border-radius: 10px;
text-decoration: none;
border: 1px solid transparent;
background: var(--accent);
color: var(--on-accent);
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.14);
white-space: nowrap;
}
.clusters-page-create-btn:hover {
filter: brightness(1.08);
}
/* Прогресс создания кластера */
.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;
}
/* Заголовок блока заданий + кнопка «Журнал» у failed/cancelled */
.jobs-msg-cell .jobs-msg-primary {
margin-bottom: 0.35rem;
}
.jobs-open-log-btn {
margin-top: 0.25rem;
font-size: 0.875rem;
}
.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;
}
@media (max-width: 767px) {
.card {
padding: 0.9rem 0.75rem;
border-radius: 9px;
}
}
.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: var(--on-accent);
cursor: pointer;
}
button:hover {
filter: brightness(1.08);
}
/* Повышенная специфичность: на синем фоне всегда белый текст (наследование color от карточки в светлой теме и т.п.) */
button:not(.btn-secondary):not(.btn-danger):not(.icon-btn):not(.theme-toggle):not(.nav-menu-toggle):not(.nav-dropdown__trigger):not(.journal-pag-btn):not(.journal-pag-num) {
color: var(--on-accent);
}
.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);
}
/* Горизонтальная прокрутка широких таблиц; на touch — плавный скролл */
.table-wrap {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
overscroll-behavior-x: contain;
margin: 0 -0.15rem;
padding: 0 0.15rem 0.25rem;
border-radius: 10px;
scrollbar-width: thin;
}
@media (max-width: 767px) {
.table-wrap {
margin: 0 -0.35rem;
padding: 0 0.35rem 0.35rem;
}
}
table {
width: 100%;
border-collapse: collapse;
font-size: 0.9rem;
}
@media (max-width: 767px) {
table {
font-size: 0.82rem;
}
th,
td {
padding: 0.4rem 0.28rem;
}
}
/* Липкий заголовок внутри прокручиваемой области */
.table-wrap thead th {
position: sticky;
top: 0;
z-index: 2;
background: var(--card);
box-shadow: 0 1px 0 var(--border);
}
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;
}
/*
* Таблица кластеров: width 100% карточки; узкие колонки — по содержимому (width: 1% + nowrap),
* свободная ширина уходит в «Имя». Текст имени до 36rem с ellipsis. «Версия» ≤ 30rem с переносом.
* Прокрутка при переполнении — в .table-wrap.
* Автор: Сергей Антропов — https://devops.org.ru
*/
#tbl-clusters {
table-layout: auto;
width: 100%;
box-sizing: border-box;
}
#tbl-clusters th.col-cluster-name,
#tbl-clusters td.col-cluster-name {
/* Остаток ширины таблицы после «1%»-колонок */
width: 100%;
min-width: 0;
max-width: none;
text-align: left;
vertical-align: middle;
overflow: hidden;
box-sizing: border-box;
}
/* Имя в одну строку; обрезка длинных имён — до 36rem, в узкой колонке — по ширине ячейки */
#tbl-clusters td.col-cluster-name .cluster-name-link {
display: inline-block;
max-width: min(36rem, 100%);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
box-sizing: border-box;
}
#tbl-clusters td.col-cluster-name .cluster-name {
white-space: nowrap;
}
/* Короткие колонки: 1% — не забирают лишнюю ширину у «Имя», фактически по min-content + nowrap */
#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 {
width: 1%;
min-width: 0;
padding-left: 0.5rem;
padding-right: 0.5rem;
text-align: center;
vertical-align: middle;
white-space: nowrap;
}
/*
* Версия: по содержимому, но max-width меньше, чем у «Имя» (36rem), иначе один docker-тег
* сделал бы эту колонку шире имени кластера.
*/
#tbl-clusters th.col-version,
#tbl-clusters td.col-version {
width: 1%;
min-width: 0;
max-width: 30rem;
padding-left: 0.5rem;
padding-right: 0.5rem;
text-align: center;
vertical-align: middle;
box-sizing: border-box;
}
#tbl-clusters th.col-version {
white-space: nowrap;
}
#tbl-clusters td.col-version {
white-space: normal;
word-break: break-word;
overflow-wrap: anywhere;
}
/* Действия: как узкая колонка по сетке 4×2 */
#tbl-clusters th.col-actions,
#tbl-clusters td.actions {
width: 1%;
min-width: 0;
max-width: none;
padding: 0.5rem 0.3rem;
text-align: center;
vertical-align: middle;
box-sizing: border-box;
}
#tbl-clusters td.actions {
white-space: normal;
overflow: visible;
}
/* Ширина > 920px: все кнопки в одну строку (6 или 7 шт., appendClusterActionButtons) */
#tbl-clusters .actions-toolbar {
display: inline-flex;
flex-wrap: nowrap;
flex-direction: row;
gap: 0.38rem;
justify-content: center;
align-items: center;
width: max-content;
max-width: 100%;
margin: 0 auto;
box-sizing: border-box;
}
#tbl-clusters .actions-toolbar .icon-tooltip-host {
display: flex;
justify-content: center;
align-items: center;
}
/* ≤920px: компактная сетка 4×2 в колонке «Действия» */
@media (max-width: 920px) {
#tbl-clusters .actions-toolbar {
display: grid;
grid-template-columns: repeat(4, 2rem);
grid-auto-rows: minmax(1.95rem, auto);
}
/* Неполная вторая строка — по центру относительно четырёх столбцов */
#tbl-clusters .actions-toolbar:has(.icon-tooltip-host:nth-child(7):last-child) .icon-tooltip-host:nth-child(5) {
grid-column: 2;
}
#tbl-clusters .actions-toolbar:has(.icon-tooltip-host:nth-child(6):last-child) .icon-tooltip-host:nth-child(5) {
grid-column: 2;
}
#tbl-clusters .actions-toolbar:has(.icon-tooltip-host:nth-child(5):last-child) .icon-tooltip-host:nth-child(5) {
grid-column: 2 / span 2;
justify-self: center;
}
}
/*
* Ширина < 920px: список кластеров — те же карточки (шапка с именем, поля, действия в одну строку).
* При ≥920px — таблица с горизонтальным скроллом в .table-wrap.
* Автор: Сергей Антропов — https://devops.org.ru
*/
@media (max-width: 919px) {
.clusters-card {
padding-left: 0.5rem;
padding-right: 0.5rem;
box-sizing: border-box;
}
.clusters-card > h2 {
font-size: 1.08rem;
font-weight: 650;
margin: 0 0 0.85rem;
padding: 0 0.15rem;
letter-spacing: -0.02em;
}
.clusters-card .table-wrap {
overflow-x: visible;
margin: 0;
padding: 0;
border-radius: 0;
}
#tbl-clusters {
min-width: 0;
width: 100%;
display: block;
border-collapse: separate;
border-spacing: 0;
}
#tbl-clusters thead {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
#tbl-clusters tbody {
display: block;
}
/* Карточка кластера: градиент, тень, скругление; внутренние зоны — через отступы у ячеек */
#tbl-clusters tbody tr {
display: block;
margin-bottom: 1.05rem;
padding: 0;
border: 1px solid var(--border);
border-radius: 16px;
box-sizing: border-box;
overflow: hidden;
background: linear-gradient(
160deg,
rgba(59, 130, 246, 0.11) 0%,
rgba(15, 23, 42, 0.55) 42%,
rgba(10, 15, 22, 0.72) 100%
);
box-shadow:
0 1px 0 rgba(255, 255, 255, 0.05) inset,
0 8px 28px rgba(0, 0, 0, 0.28);
}
html[data-theme="light"] #tbl-clusters tbody tr {
background: linear-gradient(
165deg,
rgba(255, 255, 255, 0.98) 0%,
rgba(241, 245, 249, 0.92) 48%,
rgba(226, 232, 240, 0.88) 100%
);
box-shadow:
0 1px 0 rgba(255, 255, 255, 0.9) inset,
0 6px 22px rgba(15, 23, 42, 0.09);
}
/* Шапка карточки — имя кластера (подпись и ссылка по центру) */
#tbl-clusters tbody td.col-cluster-name {
display: block;
width: 100% !important;
max-width: none !important;
margin: 0;
padding: 1rem 1rem 0.9rem;
border: none;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
background: rgba(0, 0, 0, 0.14);
box-sizing: border-box;
text-align: center;
}
html[data-theme="light"] #tbl-clusters tbody td.col-cluster-name {
border-bottom-color: rgba(15, 23, 42, 0.08);
background: rgba(59, 130, 246, 0.07);
}
#tbl-clusters tbody td.col-cluster-name::before {
content: "Кластер";
display: block;
font-size: 0.65rem;
font-weight: 650;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--muted);
margin-bottom: 0.45rem;
padding-top: 0;
opacity: 0.95;
}
#tbl-clusters tbody td.col-cluster-name .cluster-name-link {
display: inline;
max-width: none;
white-space: normal;
overflow: visible;
text-overflow: clip;
font-size: 1.12rem;
font-weight: 700;
line-height: 1.35;
word-break: break-word;
vertical-align: baseline;
}
#tbl-clusters tbody td.col-cluster-name .cluster-name {
white-space: normal;
word-break: break-word;
font-size: inherit;
}
/* Две колонки: слева подпись к левому краю, справа значение по центру */
#tbl-clusters tbody td:not(.col-cluster-name):not(.actions) {
display: grid;
grid-template-columns: minmax(5.75rem, 40%) minmax(0, 1fr);
gap: 0.45rem 0.65rem;
align-items: center;
justify-items: start;
width: 100%;
max-width: none;
box-sizing: border-box;
border: none;
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
padding: 0.55rem 1rem;
text-align: center;
vertical-align: middle;
white-space: normal;
overflow: visible;
}
#tbl-clusters tbody td.col-version {
align-items: start;
font-size: 0.78rem;
line-height: 1.45;
color: var(--fg);
word-break: break-word;
overflow-wrap: anywhere;
}
html[data-theme="light"] #tbl-clusters tbody td:not(.col-cluster-name):not(.actions) {
border-bottom-color: rgba(15, 23, 42, 0.07);
}
#tbl-clusters tbody td:not(.col-cluster-name):not(.actions)::before {
font-size: 0.72rem;
font-weight: 600;
text-transform: none;
letter-spacing: 0.02em;
color: var(--muted);
line-height: 1.3;
padding-top: 0;
justify-self: start;
text-align: left;
width: auto;
}
#tbl-clusters tbody td.col-kind::before {
content: "kind";
}
#tbl-clusters tbody td.col-kubeconfig::before {
content: "kubeconfig";
}
#tbl-clusters tbody td.col-version::before {
content: "Версия";
padding-top: 0.2rem;
}
#tbl-clusters tbody td.col-workers::before {
content: "Workers";
}
#tbl-clusters tbody td.col-state::before {
content: "Состояние";
}
#tbl-clusters tbody td:not(.col-cluster-name):not(.actions) > .badge,
#tbl-clusters tbody td:not(.col-cluster-name):not(.actions) > .muted {
justify-self: center;
width: fit-content;
max-width: 100%;
box-sizing: border-box;
text-align: center;
}
/* Версия и workers: обёртка в разметке (dashboard.js) — явно по центру правой колонки */
#tbl-clusters tbody td.col-version .cluster-list-value,
#tbl-clusters tbody td.col-workers .cluster-list-value {
display: block;
justify-self: center;
width: 100%;
max-width: 100%;
box-sizing: border-box;
text-align: center;
}
#tbl-clusters tbody td:last-child:not(.actions) {
border-bottom: none;
}
/* Страница кластера (<920): две колонки — подпись слева, значение по центру */
.cluster-meta-tile {
display: grid;
grid-template-columns: minmax(5.5rem, 42%) minmax(0, 1fr);
gap: 0.35rem 0.55rem;
align-items: center;
text-align: center;
}
.cluster-meta-tile__label {
justify-self: start;
text-align: left;
width: auto;
}
.cluster-meta-tile__value {
justify-self: stretch;
justify-content: center;
text-align: center;
width: 100%;
}
.cluster-meta-tile__value .badge {
width: fit-content;
max-width: 100%;
margin-left: auto;
margin-right: auto;
box-sizing: border-box;
}
.cluster-meta-tile__value .cluster-meta-version-tag,
.cluster-meta-tile__value .cluster-meta-workers {
display: block;
margin-left: auto;
margin-right: auto;
width: fit-content;
max-width: 100%;
text-align: center;
}
/* Панель действий — отдельная «подошва» карточки */
#tbl-clusters tbody td.actions {
display: block;
grid-template-columns: none;
max-width: none !important;
width: 100%;
margin: 0;
padding: 0.75rem 0.85rem 0.95rem;
border: none;
border-top: 1px solid rgba(255, 255, 255, 0.07);
background: rgba(0, 0, 0, 0.2);
text-align: center;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
overscroll-behavior-x: contain;
scrollbar-width: thin;
box-sizing: border-box;
}
html[data-theme="light"] #tbl-clusters tbody td.actions {
border-top-color: rgba(15, 23, 42, 0.08);
background: rgba(15, 23, 42, 0.04);
}
#tbl-clusters tbody td.actions::before {
content: "Действия";
display: block;
font-size: 0.65rem;
font-weight: 650;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--muted);
margin-bottom: 0.55rem;
opacity: 0.95;
}
/* Все иконки действий в одну строку (6–7 шт.); узкий экран — горизонтальный скролл у ячейки */
#tbl-clusters tbody td.actions .actions-toolbar {
display: inline-flex;
flex-direction: row;
flex-wrap: nowrap;
gap: 0.42rem;
justify-content: center;
align-items: center;
width: max-content;
max-width: none;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border-radius: 12px;
background: rgba(0, 0, 0, 0.12);
border: 1px solid rgba(255, 255, 255, 0.06);
box-sizing: border-box;
}
html[data-theme="light"] #tbl-clusters tbody td.actions .actions-toolbar {
background: rgba(255, 255, 255, 0.55);
border-color: rgba(59, 130, 246, 0.15);
}
#tbl-clusters tbody td.actions .actions-toolbar .icon-tooltip-host {
display: flex;
flex-shrink: 0;
justify-content: center;
align-items: center;
}
/*
* Страница создания кластера: «Последние задания» (#tbl-jobs) — карточки как у списка кластеров.
* Автор: Сергей Антропов — https://devops.org.ru
*/
.jobs-card {
padding-left: 0.5rem;
padding-right: 0.5rem;
box-sizing: border-box;
}
.jobs-card .table-wrap {
overflow-x: visible;
margin: 0;
padding: 0;
border-radius: 0;
}
.jobs-card .jobs-card-toolbar {
flex-wrap: wrap;
gap: 0.5rem 0.75rem;
align-items: center;
}
.jobs-card #tbl-jobs {
min-width: 0 !important;
width: 100%;
display: block;
border-collapse: separate;
border-spacing: 0;
}
.jobs-card #tbl-jobs thead {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.jobs-card #tbl-jobs tbody {
display: block;
}
.jobs-card #tbl-jobs tbody tr.journal-data-row {
display: block;
padding: 0;
border: 1px solid var(--border);
border-radius: 16px;
box-sizing: border-box;
overflow: hidden;
margin-bottom: 1.05rem;
background: linear-gradient(
160deg,
rgba(59, 130, 246, 0.11) 0%,
rgba(15, 23, 42, 0.55) 42%,
rgba(10, 15, 22, 0.72) 100%
);
box-shadow:
0 1px 0 rgba(255, 255, 255, 0.05) inset,
0 8px 28px rgba(0, 0, 0, 0.28);
}
html[data-theme="light"] .jobs-card #tbl-jobs tbody tr.journal-data-row {
background: linear-gradient(
165deg,
rgba(255, 255, 255, 0.98) 0%,
rgba(241, 245, 249, 0.92) 48%,
rgba(226, 232, 240, 0.88) 100%
);
box-shadow:
0 1px 0 rgba(255, 255, 255, 0.9) inset,
0 6px 22px rgba(15, 23, 42, 0.09);
}
.jobs-card #tbl-jobs tbody tr.journal-data-row:has(+ tr.journal-details-row:not(.hidden)) {
border-bottom: none;
border-radius: 16px 16px 0 0;
margin-bottom: 0;
}
.jobs-card #tbl-jobs tbody tr.journal-details-row:not(.hidden) {
display: block;
margin-bottom: 1.05rem;
padding: 0;
border: 1px solid var(--border);
border-top: 1px solid rgba(255, 255, 255, 0.06);
border-radius: 0 0 16px 16px;
box-sizing: border-box;
overflow: hidden;
background: rgba(0, 0, 0, 0.2);
}
html[data-theme="light"] .jobs-card #tbl-jobs tbody tr.journal-details-row:not(.hidden) {
border-top-color: rgba(15, 23, 42, 0.08);
background: rgba(15, 23, 42, 0.04);
}
.jobs-card #tbl-jobs tbody tr.journal-details-row:not(.hidden) td {
display: block;
width: 100% !important;
border: none;
padding: 0.65rem 0.85rem 0.85rem;
box-sizing: border-box;
}
.jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td:not(.create-jobs-card-td--log) {
display: grid;
grid-template-columns: minmax(6.5rem, 40%) minmax(0, 1fr);
gap: 0.45rem 0.65rem;
align-items: center;
justify-items: start;
width: 100%;
max-width: none;
box-sizing: border-box;
border: none;
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
padding: 0.55rem 1rem;
text-align: center;
white-space: normal;
overflow: visible;
}
html[data-theme="light"]
.jobs-card
#tbl-jobs
tbody
tr.journal-data-row
td.create-jobs-card-td:not(.create-jobs-card-td--log) {
border-bottom-color: rgba(15, 23, 42, 0.07);
}
.jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td--time {
align-items: start;
}
.jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td:not(.create-jobs-card-td--log)::before {
font-size: 0.72rem;
font-weight: 600;
text-transform: none;
letter-spacing: 0.02em;
color: var(--muted);
line-height: 1.3;
justify-self: start;
text-align: left;
width: auto;
}
.jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td--time::before {
content: "Завершено (UTC)";
padding-top: 0.15rem;
}
.jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td--cluster::before {
content: "Кластер";
}
.jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td--kind::before {
content: "Тип задания";
}
.jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td--status::before {
content: "Статус";
}
.jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td--msg::before {
content: "Сообщение";
align-self: start;
padding-top: 0.2rem;
}
.jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td--msg {
align-items: start;
}
.jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td--cluster .journal-code,
.jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td--kind .journal-code {
display: inline-block;
justify-self: center;
width: fit-content;
max-width: 100%;
text-align: center;
word-break: break-word;
}
.jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td--status > span {
display: inline-block;
justify-self: center;
width: fit-content;
max-width: 100%;
}
.jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td--time > .journal-time-stack {
display: flex;
flex-direction: column;
align-items: center;
justify-self: center;
width: 100%;
text-align: center;
gap: 0.12rem;
}
.jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td--msg .create-jobs-msg-value {
display: block;
justify-self: center;
width: 100%;
max-width: 100%;
text-align: center;
word-break: break-word;
overflow-wrap: anywhere;
line-height: 1.4;
}
.jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td--log {
display: block;
width: 100% !important;
max-width: none !important;
margin: 0;
padding: 0.75rem 0.85rem 0.95rem;
border: none;
border-top: 1px solid rgba(255, 255, 255, 0.07);
background: rgba(0, 0, 0, 0.2);
text-align: center;
white-space: normal;
box-sizing: border-box;
}
html[data-theme="light"] .jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td--log {
border-top-color: rgba(15, 23, 42, 0.08);
background: rgba(15, 23, 42, 0.04);
}
.jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td--log::before {
content: "Лог";
display: block;
font-size: 0.65rem;
font-weight: 650;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--muted);
margin-bottom: 0.55rem;
opacity: 0.95;
}
.jobs-card #tbl-jobs tbody tr.journal-data-row td.create-jobs-card-td--log .btn-journal-toggle {
margin-left: auto;
margin-right: auto;
}
}
.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;
}
.job-log-modal-overlay {
z-index: 500;
}
.modal-box--job-log .job-log-modal-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--job-log .job-log-modal-body {
background: rgba(0, 0, 0, 0.04);
}
.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-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: clamp(1.15rem, 4.5vw, 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;
}
/* Скриншоты в app/docs/screenshots.md: не вылезают за карточку */
.readme-section-card.markdown-body img {
max-width: 100%;
height: auto;
border-radius: 8px;
margin: 0.5rem 0;
border: 1px solid var(--color-border-subtle, rgba(128, 128, 128, 0.25));
}
.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: center;
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: center;
}
.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;
}
/* Карточка «Установленные аддоны» на странице кластера (отдельный section.card) */
.cluster-detail-addons-card.hidden {
display: none;
}
.cluster-detail-addons-card__header {
margin-bottom: 1rem;
}
.cluster-detail-addons-card__head-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.5rem 0.75rem;
margin-bottom: 0.45rem;
}
/* Бейдж и заголовок в одной линии по вертикали: сброс margin у .cluster-detail-section-title (он задаётся ниже по файлу). */
.cluster-detail-addons-card__head-row h2.cluster-detail-section-title {
margin: 0;
line-height: 1.25;
}
.cluster-detail-addons-card__helm-badge {
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
align-self: center;
padding: 0.22rem 0.55rem;
min-height: 1.35em;
font-size: 0.68rem;
font-weight: 700;
line-height: 1;
letter-spacing: 0.06em;
text-transform: uppercase;
color: #fff;
border-radius: 6px;
background: linear-gradient(135deg, #0f766e 0%, #0d9488 40%, #14b8a6 100%);
box-shadow: 0 1px 3px rgba(15, 118, 110, 0.35);
}
.cluster-detail-addons-card__title {
margin: 0;
font-size: 1.12rem;
font-weight: 700;
letter-spacing: -0.02em;
line-height: 1.25;
}
.cluster-detail-addons-card__lead {
margin: 0;
max-width: 44rem;
font-size: 0.86rem;
line-height: 1.5;
}
.cluster-detail-addons-card__lead code {
font-size: 0.82em;
}
.cluster-detail-addons-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(15.5rem, 1fr));
gap: 0.75rem 1rem;
width: 100%;
box-sizing: border-box;
}
.cluster-detail-addon-mini {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 0.35rem;
padding: 0.75rem 0.85rem 0.7rem;
min-height: 5.5rem;
border-radius: 10px;
border: 1px solid var(--border);
border-left: 4px solid rgba(59, 130, 246, 0.75);
background: var(--surface);
color: inherit;
text-decoration: none;
box-sizing: border-box;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
transition:
border-color 0.18s ease,
box-shadow 0.18s ease,
transform 0.15s ease,
background 0.18s ease;
}
html[data-theme="light"] .cluster-detail-addon-mini {
box-shadow: 0 2px 10px rgba(15, 23, 42, 0.06);
}
.cluster-detail-addon-mini:hover {
border-color: rgba(59, 130, 246, 0.4);
box-shadow: 0 6px 20px rgba(59, 130, 246, 0.12);
transform: translateY(-2px);
background: rgba(59, 130, 246, 0.04);
}
.cluster-detail-addon-mini:focus-visible {
outline: 2px solid rgba(59, 130, 246, 0.65);
outline-offset: 3px;
}
.cluster-detail-addon-mini__title {
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
font-weight: 600;
font-size: 0.82rem;
line-height: 1.3;
color: var(--text);
}
.cluster-detail-addon-mini__ver {
font-size: 0.78rem;
line-height: 1.4;
color: var(--muted);
word-break: break-word;
flex: 1 1 auto;
}
.cluster-detail-addon-mini__ns {
display: inline-flex;
align-items: center;
margin-top: auto;
padding: 0.15rem 0.4rem;
font-size: 0.7rem;
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
color: var(--muted);
background: rgba(0, 0, 0, 0.12);
border-radius: 4px;
}
html[data-theme="light"] .cluster-detail-addon-mini__ns {
background: rgba(15, 23, 42, 0.06);
}
.cluster-detail-addons-card__footer {
margin-top: 1rem;
padding-top: 0.85rem;
border-top: 1px solid var(--border);
}
.cluster-detail-addons-card__cta {
font-size: 0.88rem;
font-weight: 600;
color: rgba(59, 130, 246, 0.95);
text-decoration: none;
transition: color 0.15s ease;
}
.cluster-detail-addons-card__cta:hover {
color: rgba(96, 165, 250, 1);
text-decoration: underline;
}
.cluster-detail-addons-card__cta:focus-visible {
outline: 2px solid rgba(59, 130, 246, 0.55);
outline-offset: 2px;
border-radius: 4px;
}
.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: center;
width: 100%;
max-width: 28rem;
margin-inline: auto;
}
.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;
}
/* Заголовок карточки K8s + выпадающий фильтр namespace справа */
.cluster-k8s-card-header {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 0.5rem 1rem;
margin-bottom: 0.55rem;
}
.cluster-k8s-card-header .cluster-detail-section-title {
margin: 0;
flex: 1 1 auto;
min-width: 0;
}
.cluster-k8s-ns-filter-wrap {
flex: 0 0 auto;
}
.cluster-k8s-ns-select {
width: auto;
min-width: 10rem;
max-width: min(18rem, 100%);
margin: 0;
padding: 0.35rem 0.5rem;
font-size: 0.88rem;
}
/* Сетка карточек узлов на странице кластера: не более 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;
overscroll-behavior-x: contain;
border-radius: 8px;
border: 1px solid var(--border);
background: rgba(0, 0, 0, 0.12);
scrollbar-width: thin;
}
html[data-theme="light"] .cluster-k8s-table-scroll {
background: rgba(15, 23, 42, 0.04);
}
.cluster-k8s-table {
width: 100%;
min-width: 32rem;
border-collapse: collapse;
font-size: 0.8rem;
}
@media (max-width: 767px) {
.cluster-k8s-table {
min-width: 28rem;
font-size: 0.76rem;
}
}
.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;
}
@media (max-width: 767px) {
.cluster-k8s-table th,
.cluster-k8s-table td {
padding: 0.32rem 0.4rem;
}
}
.cluster-k8s-table th {
font-weight: 650;
color: var(--muted);
white-space: nowrap;
background: rgba(0, 0, 0, 0.18);
position: sticky;
top: 0;
z-index: 2;
box-shadow: 0 1px 0 var(--border);
}
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);
}
/* Полноэкранный спиннер первой загрузки главной панели, /cluster-create, /documentation */
body.dashboard-home-loading,
body.dashboard-create-loading,
body.documentation-page-loading {
overflow: hidden;
}
/* Полноэкранный спиннер первой загрузки страницы кластера */
body.cluster-page-loading {
overflow: hidden;
}
/* Первая загрузка страниц «Аддоны» и «Журнал» */
body.cluster-addons-page-loading,
body.journal-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: var(--on-accent);
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;
}
/* Страница «Аддоны»: Helm-чарты по выбранному кластеру */
.cluster-addons-toolbar-card .cluster-addons-cluster-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.65rem 1rem;
margin-bottom: 0.35rem;
}
.cluster-addons-cluster-label {
display: block;
width: 100%;
font-size: 0.8125rem;
font-weight: 600;
margin-bottom: 0.2rem;
}
.cluster-addons-cluster-select {
min-width: min(100%, 18rem);
flex: 1 1 14rem;
max-width: 28rem;
}
.cluster-addons-status-bar {
margin-top: 0.85rem;
}
.cluster-addons-status-bar--message .cluster-addons-status-msg {
margin: 0;
font-size: 0.88rem;
line-height: 1.45;
}
.cluster-addons-status-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr));
gap: 0.65rem;
}
.cluster-addons-status-card {
border-radius: 10px;
border: 1px solid var(--border);
padding: 0.65rem 0.75rem;
background: rgba(0, 0, 0, 0.14);
display: flex;
flex-direction: column;
gap: 0.35rem;
min-height: 3.5rem;
justify-content: center;
transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
html[data-theme="light"] .cluster-addons-status-card {
background: rgba(15, 23, 42, 0.04);
}
.cluster-addons-status-card--on {
border-color: rgba(34, 197, 94, 0.45);
box-shadow: 0 0 0 1px rgba(34, 197, 94, 0.12);
}
.cluster-addons-status-card--off {
border-color: var(--border);
opacity: 0.92;
}
.cluster-addons-status-card__label {
font-size: 0.78rem;
font-weight: 600;
color: var(--muted);
line-height: 1.25;
word-break: break-word;
}
.cluster-addons-status-card__value {
font-size: 1.05rem;
font-weight: 700;
letter-spacing: 0.02em;
}
.cluster-addons-status-card--on .cluster-addons-status-card__value {
color: rgb(34, 197, 94);
}
.cluster-addons-status-card--off .cluster-addons-status-card__value {
color: var(--muted);
}
.cluster-addons-grid {
display: grid;
grid-template-columns: minmax(0, 1fr);
gap: 1rem;
margin: 1rem 0;
}
/* Шапка карточки аддона: заголовок + бейдж «установлен» справа */
.cluster-addon-card__header {
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: space-between;
gap: 0.65rem;
margin-bottom: 0.35rem;
}
.cluster-addon-card__header .cluster-addon-card__title {
margin: 0;
flex: 1 1 auto;
min-width: 0;
font-size: 1.05rem;
line-height: 1.3;
}
.cluster-addon-card__badge {
flex: 0 0 auto;
font-size: 0.68rem;
font-weight: 700;
letter-spacing: 0.03em;
text-transform: uppercase;
padding: 0.28rem 0.5rem;
border-radius: 6px;
border: 1px solid var(--border);
line-height: 1.2;
white-space: nowrap;
}
.cluster-addon-card__badge--on {
border-color: rgba(34, 197, 94, 0.5);
color: rgb(34, 197, 94);
background: rgba(34, 197, 94, 0.1);
}
.cluster-addon-card__badge--off {
color: var(--muted);
background: rgba(0, 0, 0, 0.12);
}
html[data-theme="light"] .cluster-addon-card__badge--off {
background: rgba(15, 23, 42, 0.06);
}
.cluster-addon-card__values-details {
margin: 0.75rem 0 0;
border-radius: 8px;
border: 1px solid var(--border);
padding: 0.5rem 0.65rem;
background: rgba(0, 0, 0, 0.08);
}
html[data-theme="light"] .cluster-addon-card__values-details {
background: rgba(15, 23, 42, 0.03);
}
.cluster-addon-card__values-summary {
cursor: pointer;
font-weight: 600;
font-size: 0.88rem;
list-style-position: outside;
padding: 0.15rem 0;
}
.cluster-addon-card__values-hint {
margin: 0.5rem 0 0.45rem;
font-size: 0.78rem;
line-height: 1.45;
}
.cluster-addon-card__values-subhead {
margin: 0.65rem 0 0.35rem;
font-size: 0.8rem;
font-weight: 700;
color: var(--text);
}
.cluster-addon-card__values-details .cluster-addon-card__values-subhead:first-of-type {
margin-top: 0.35rem;
}
.cluster-addon-card__values-textarea {
display: block;
width: 100%;
box-sizing: border-box;
margin: 0;
min-height: 6rem;
padding: 0.5rem 0.6rem;
font-size: 0.78rem;
line-height: 1.4;
border-radius: 6px;
border: 1px solid var(--border);
background: rgba(0, 0, 0, 0.18);
color: inherit;
resize: vertical;
}
html[data-theme="light"] .cluster-addon-card__values-textarea {
background: rgba(255, 255, 255, 0.85);
}
.cluster-addon-card__desc {
margin: 0 0 0.75rem;
font-size: 0.85rem;
line-height: 1.45;
}
/* Кнопки «Установить / Обновить / Удалить» — по содержимому, не на всю ширину карточки */
.cluster-addon-card__actions--inline {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-top: 0.85rem;
gap: 0.5rem;
align-items: center;
justify-content: flex-start;
}
.cluster-addon-card__actions--inline .btn-addon-install,
.cluster-addon-card__actions--inline .btn-addon-remove {
flex: 0 0 auto;
min-width: 7.5rem;
min-height: 2.65rem;
margin-top: 0;
box-sizing: border-box;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.5rem 1rem;
font-size: 0.9rem;
}
.cluster-addon-card--wide {
grid-column: 1;
}
.cluster-addon-istio-grid {
margin-top: 0.25rem;
}
.cluster-addon-istio-load-field {
grid-column: 1 / -1;
}
.cluster-addon-card__field-label {
display: block;
margin-bottom: 0.35rem;
font-size: 0.88rem;
font-weight: 600;
color: var(--text);
}
.cluster-addon-version-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.5rem 0.65rem;
}
.cluster-addon-version-row .cluster-addons-version-select {
flex: 1 1 12rem;
width: auto;
min-width: 10rem;
max-width: 22rem;
}
.cluster-addon-card__values-panel {
margin-top: 0.65rem;
}
.btn-addon-load-values {
flex: 0 0 auto;
white-space: nowrap;
}
/* Якорь для блока прогресса до первой операции; пустой, когда секция перенесена в карточку */
.cluster-addons-helm-dock:empty {
display: none;
}
.cluster-addons-helm-dock:not(:empty) {
margin-bottom: 1.5rem;
}
/* Карточка хода Helm на странице аддонов (разметка как у create-progress-wrap + job-log-panel) */
.cluster-addons-helm-progress {
margin-bottom: 1.5rem;
}
.cluster-addon-card > .cluster-addons-helm-progress {
margin-top: 1rem;
margin-bottom: 0;
width: 100%;
box-sizing: border-box;
}
.cluster-addons-helm-progress .job-log-panel {
max-height: min(55vh, 420px);
}
.cluster-addons-bootstrap-msg {
margin: 0.5rem 0 0;
font-size: 0.88rem;
line-height: 1.45;
}
/* Версии чартов на странице аддонов */
.cluster-addons-version-select {
width: 100%;
max-width: 22rem;
padding: 0.45rem 0.6rem;
font-size: 0.9rem;
border-radius: 8px;
border: 1px solid var(--border);
background: var(--surface);
color: var(--text);
}
/* Страница «Журнал» */
.journal-toolbar-card .journal-toolbar-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.75rem 1rem;
margin-top: 0.35rem;
}
.journal-status {
margin: 0.65rem 0 0;
}
.journal-empty {
margin: 0.5rem 0;
}
.journal-table-wrap {
overflow-x: auto;
margin-top: 0.5rem;
-webkit-overflow-scrolling: touch;
overscroll-behavior-x: contain;
border-radius: 10px;
scrollbar-width: thin;
}
.journal-table {
width: 100%;
min-width: 28rem;
border-collapse: collapse;
font-size: 0.85rem;
}
@media (max-width: 767px) {
.journal-table {
font-size: 0.8rem;
min-width: 22rem;
}
}
.journal-table th,
.journal-table td {
padding: 0.45rem 0.55rem;
text-align: left;
border-bottom: 1px solid var(--border);
vertical-align: top;
}
@media (max-width: 767px) {
.journal-table th,
.journal-table td {
padding: 0.38rem 0.4rem;
}
}
.journal-table th {
font-weight: 600;
color: var(--muted);
position: sticky;
top: 0;
z-index: 2;
background: var(--card);
box-shadow: 0 1px 0 var(--border);
}
.journal-code {
font-size: 0.8rem;
}
.journal-cell-time {
white-space: nowrap;
}
/* Дата и время в одну строку на широком экране; до 920px — в две строки (дата / время), как в журнале и таблицах */
.journal-time-stack {
display: inline-flex;
flex-direction: row;
flex-wrap: nowrap;
align-items: baseline;
gap: 0.35em;
}
.journal-time-date,
.journal-time-clock {
font-variant-numeric: tabular-nums;
}
@media (max-width: 919px) {
.journal-time-stack {
flex-direction: column;
align-items: flex-start;
gap: 0.12rem;
}
.journal-cell-time {
white-space: normal;
vertical-align: top;
}
}
.journal-cell-msg {
max-width: 14rem;
word-break: break-word;
}
.journal-cell-actions {
white-space: nowrap;
}
.journal-status-pill {
display: inline-block;
padding: 0.12rem 0.45rem;
border-radius: 999px;
font-size: 0.78rem;
background: rgba(148, 163, 184, 0.2);
}
.journal-status-pill--ok {
background: rgba(34, 197, 94, 0.2);
color: var(--text);
}
.journal-status-pill--err {
background: rgba(239, 68, 68, 0.2);
}
.journal-status-pill--warn {
background: rgba(234, 179, 8, 0.22);
}
.journal-details-cell {
padding: 0.5rem 0.55rem 0.85rem;
background: rgba(0, 0, 0, 0.08);
}
html[data-theme="light"] .journal-details-cell {
background: rgba(15, 23, 42, 0.04);
}
.journal-log-pre {
margin: 0;
max-height: min(40vh, 18rem);
overflow: auto;
padding: 0.5rem 0.65rem;
font-size: 0.76rem;
line-height: 1.35;
white-space: pre-wrap;
word-break: break-word;
border-radius: 8px;
border: 1px solid var(--border);
}
/*
* Журнал: при ширине < 620px список записей — карточки (та же сетка, что «Последние задания» на /cluster-create).
* Разметка строк задаётся в journal.js (классы create-jobs-card-td*).
* Автор: Сергей Антропов — https://devops.org.ru
*/
@media (max-width: 619px) {
.journal-list-card {
padding-left: 0.5rem;
padding-right: 0.5rem;
box-sizing: border-box;
}
.journal-list-card .journal-table-wrap {
overflow-x: visible;
margin-top: 0.5rem;
padding: 0;
border-radius: 0;
}
.journal-list-card #journal-table {
min-width: 0 !important;
width: 100%;
display: block;
border-collapse: separate;
border-spacing: 0;
}
.journal-list-card #journal-table thead {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.journal-list-card #journal-table tbody {
display: block;
}
.journal-list-card #journal-table tbody tr.journal-data-row {
display: block;
padding: 0;
border: 1px solid var(--border);
border-radius: 16px;
box-sizing: border-box;
overflow: hidden;
margin-bottom: 1.05rem;
background: linear-gradient(
160deg,
rgba(59, 130, 246, 0.11) 0%,
rgba(15, 23, 42, 0.55) 42%,
rgba(10, 15, 22, 0.72) 100%
);
box-shadow:
0 1px 0 rgba(255, 255, 255, 0.05) inset,
0 8px 28px rgba(0, 0, 0, 0.28);
}
html[data-theme="light"] .journal-list-card #journal-table tbody tr.journal-data-row {
background: linear-gradient(
165deg,
rgba(255, 255, 255, 0.98) 0%,
rgba(241, 245, 249, 0.92) 48%,
rgba(226, 232, 240, 0.88) 100%
);
box-shadow:
0 1px 0 rgba(255, 255, 255, 0.9) inset,
0 6px 22px rgba(15, 23, 42, 0.09);
}
.journal-list-card #journal-table tbody tr.journal-data-row:has(+ tr.journal-details-row:not(.hidden)) {
border-bottom: none;
border-radius: 16px 16px 0 0;
margin-bottom: 0;
}
.journal-list-card #journal-table tbody tr.journal-details-row:not(.hidden) {
display: block;
margin-bottom: 1.05rem;
padding: 0;
border: 1px solid var(--border);
border-top: 1px solid rgba(255, 255, 255, 0.06);
border-radius: 0 0 16px 16px;
box-sizing: border-box;
overflow: hidden;
background: rgba(0, 0, 0, 0.2);
}
html[data-theme="light"] .journal-list-card #journal-table tbody tr.journal-details-row:not(.hidden) {
border-top-color: rgba(15, 23, 42, 0.08);
background: rgba(15, 23, 42, 0.04);
}
.journal-list-card #journal-table tbody tr.journal-details-row:not(.hidden) td {
display: block;
width: 100% !important;
border: none;
padding: 0.65rem 0.85rem 0.85rem;
box-sizing: border-box;
}
.journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td:not(.create-jobs-card-td--log) {
display: grid;
grid-template-columns: minmax(6.5rem, 40%) minmax(0, 1fr);
gap: 0.45rem 0.65rem;
align-items: center;
justify-items: start;
width: 100%;
max-width: none;
box-sizing: border-box;
border: none;
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
padding: 0.55rem 1rem;
text-align: center;
white-space: normal;
overflow: visible;
}
html[data-theme="light"]
.journal-list-card
#journal-table
tbody
tr.journal-data-row
td.create-jobs-card-td:not(.create-jobs-card-td--log) {
border-bottom-color: rgba(15, 23, 42, 0.07);
}
.journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td--time {
align-items: start;
}
.journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td:not(.create-jobs-card-td--log)::before {
font-size: 0.72rem;
font-weight: 600;
text-transform: none;
letter-spacing: 0.02em;
color: var(--muted);
line-height: 1.3;
justify-self: start;
text-align: left;
width: auto;
}
.journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td--time::before {
content: "Завершено (UTC)";
padding-top: 0.15rem;
}
.journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td--cluster::before {
content: "Кластер";
}
.journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td--kind::before {
content: "Тип / операция";
}
.journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td--status::before {
content: "Статус";
}
.journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td--msg::before {
content: "Сообщение";
align-self: start;
padding-top: 0.2rem;
}
.journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td--msg {
align-items: start;
}
.journal-list-card #journal-table tbody tr.journal-data-row .journal-cell-kind {
max-width: none;
}
.journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td--cluster .journal-code,
.journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td--kind .journal-code {
display: inline-block;
justify-self: center;
width: fit-content;
max-width: 100%;
text-align: center;
word-break: break-word;
}
.journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td--status > span {
display: inline-block;
justify-self: center;
width: fit-content;
max-width: 100%;
}
.journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td--time > .journal-time-stack {
display: flex;
flex-direction: column;
align-items: center;
justify-self: center;
width: 100%;
text-align: center;
gap: 0.12rem;
}
.journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td--msg .create-jobs-msg-value {
display: block;
justify-self: center;
width: 100%;
max-width: 100%;
text-align: center;
word-break: break-word;
overflow-wrap: anywhere;
line-height: 1.4;
}
.journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td--log {
display: block;
width: 100% !important;
max-width: none !important;
margin: 0;
padding: 0.75rem 0.85rem 0.95rem;
border: none;
border-top: 1px solid rgba(255, 255, 255, 0.07);
background: rgba(0, 0, 0, 0.2);
text-align: center;
white-space: normal;
box-sizing: border-box;
}
html[data-theme="light"] .journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td--log {
border-top-color: rgba(15, 23, 42, 0.08);
background: rgba(15, 23, 42, 0.04);
}
.journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td--log::before {
content: "Лог";
display: block;
font-size: 0.65rem;
font-weight: 650;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--muted);
margin-bottom: 0.55rem;
opacity: 0.95;
}
.journal-list-card #journal-table tbody tr.journal-data-row td.create-jobs-card-td--log .btn-journal-toggle {
margin-left: auto;
margin-right: auto;
}
}
/* Три сегмента на странице журнала — шире блок переключателя */
.journal-toolbar-card .cluster-edit-segmented {
max-width: 100%;
flex-wrap: wrap;
}
@media (min-width: 960px) {
.journal-toolbar-card .cluster-edit-segmented {
flex-wrap: nowrap;
max-width: 56rem;
}
}
.journal-view-fieldset {
margin-bottom: 0.25rem;
}
.journal-cluster-picker {
margin-top: 1rem;
margin-bottom: 0.5rem;
}
.journal-cluster-picker.hidden {
display: none;
}
.journal-cluster-picker-label {
display: block;
font-size: 0.88rem;
font-weight: 600;
margin-bottom: 0.35rem;
}
.journal-cluster-select {
width: 100%;
max-width: 24rem;
padding: 0.45rem 0.65rem;
font-size: 0.9rem;
border-radius: 8px;
border: 1px solid var(--border);
background: var(--surface);
color: var(--text);
}
.journal-cluster-picker-hint {
margin: 0.45rem 0 0;
font-size: 0.84rem;
max-width: 40rem;
}
.journal-toolbar-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.75rem 1rem;
margin-top: 0.65rem;
}
.journal-cell-kind {
word-break: break-word;
max-width: 12rem;
}
/* Пагинация журнала: компактно, в одну строку (при нехватке места — горизонтальный скролл) */
.journal-pagination {
margin-top: 1.25rem;
padding-top: 1rem;
border-top: 1px solid var(--border);
}
.journal-pagination-inner {
display: flex;
flex-wrap: nowrap;
align-items: center;
justify-content: center;
gap: 0.18rem 0.32rem;
max-width: 100%;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
overscroll-behavior-x: contain;
scrollbar-width: thin;
padding-bottom: 0.15rem;
box-sizing: border-box;
}
.journal-pagination-inner::-webkit-scrollbar {
height: 4px;
}
.journal-pagination-inner::-webkit-scrollbar-thumb {
background: var(--border);
border-radius: 4px;
}
.journal-pag-btn {
padding: 0.26rem 0.42rem;
font-size: 0.72rem;
font-weight: 600;
line-height: 1.2;
border-radius: 6px;
border: 1px solid var(--border);
background: var(--surface);
color: var(--text);
cursor: pointer;
flex-shrink: 0;
white-space: nowrap;
transition: background 0.15s ease, border-color 0.15s ease;
}
.journal-pag-btn:hover:not(:disabled) {
background: rgba(99, 102, 241, 0.12);
border-color: rgba(99, 102, 241, 0.45);
}
.journal-pag-btn:disabled {
opacity: 0.4;
cursor: not-allowed;
}
.journal-pag-pages {
display: flex;
flex-wrap: nowrap;
align-items: center;
gap: 0.12rem;
margin: 0 0.06rem;
flex-shrink: 0;
}
.journal-pag-num {
min-width: 1.6rem;
padding: 0.26rem 0.34rem;
font-size: 0.74rem;
font-weight: 600;
line-height: 1.2;
border-radius: 6px;
border: 1px solid transparent;
background: transparent;
color: var(--text);
cursor: pointer;
flex-shrink: 0;
white-space: nowrap;
transition: background 0.15s ease, color 0.15s ease;
}
.journal-pag-num:hover:not(:disabled) {
background: rgba(99, 102, 241, 0.1);
}
.journal-pag-num--active {
background: linear-gradient(135deg, rgba(99, 102, 241, 0.35), rgba(129, 140, 248, 0.25));
border-color: rgba(99, 102, 241, 0.5);
color: var(--text);
cursor: default;
box-shadow: 0 1px 4px rgba(99, 102, 241, 0.18);
}
.journal-pag-ellipsis {
padding: 0 0.08rem;
color: var(--muted);
font-size: 0.78rem;
user-select: none;
flex-shrink: 0;
}
/*
* Вьюпорт до 480px: компактная главная, кластеры, страница кластера, журнал, документация.
* Автор: Сергей Антропов — https://devops.org.ru
*/
@media (max-width: 479px) {
.clusters-page-hero-row {
flex-direction: column;
align-items: center;
text-align: center;
}
.clusters-page-hero-text {
flex: none;
width: 100%;
text-align: center;
}
.clusters-page-hero-actions {
flex: none;
align-self: center;
width: 100%;
margin-left: 0 !important;
justify-content: center;
padding-top: 0.25rem;
}
.clusters-page-create-btn {
margin-left: auto;
margin-right: auto;
}
.cluster-detail-hero-layout {
align-items: flex-start;
}
.cluster-detail-hero-meta {
align-self: stretch;
width: 100%;
max-width: none;
}
.journal-pagination {
margin-top: 0.85rem;
padding-top: 0.65rem;
}
.journal-pagination-inner {
gap: 0.12rem 0.22rem;
}
.journal-pag-btn {
padding: 0.22rem 0.36rem;
font-size: 0.68rem;
}
.journal-pag-pages {
gap: 0.08rem;
}
.journal-pag-num {
min-width: 1.45rem;
padding: 0.22rem 0.28rem;
font-size: 0.7rem;
}
.journal-pag-ellipsis {
font-size: 0.72rem;
padding: 0 0.06rem;
}
/* Таблицы kubectl: строка ресурса = мини-карточка (data-label задаётся в clusterK8sBuildTable) */
.cluster-k8s-table-scroll {
overflow-x: visible;
border: none;
background: transparent;
}
.cluster-k8s-table {
display: block;
width: 100%;
min-width: 0;
border-collapse: separate;
border-spacing: 0;
}
.cluster-k8s-table thead {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.cluster-k8s-table tbody {
display: block;
}
.cluster-k8s-table tbody tr {
display: block;
margin-bottom: 0.65rem;
padding: 0.55rem 0.65rem;
border: 1px solid var(--border);
border-radius: 10px;
background: rgba(0, 0, 0, 0.1);
box-sizing: border-box;
}
html[data-theme="light"] .cluster-k8s-table tbody tr {
background: rgba(59, 130, 246, 0.05);
}
.cluster-k8s-table tbody td {
display: grid;
grid-template-columns: minmax(5.25rem, 38%) minmax(0, 1fr);
gap: 0.28rem 0.45rem;
align-items: center;
justify-items: start;
width: 100% !important;
max-width: none;
border: none;
border-bottom: 1px solid var(--border);
padding: 0.4rem 0;
white-space: normal;
vertical-align: top;
word-break: break-word;
overflow-wrap: anywhere;
text-align: center;
}
.cluster-k8s-table tbody td > * {
justify-self: center;
text-align: center;
}
.cluster-k8s-table tbody td .badge {
width: fit-content;
max-width: 100%;
box-sizing: border-box;
}
.cluster-k8s-table tbody td:last-child {
border-bottom: none;
white-space: normal;
}
.cluster-k8s-table tbody td::before {
content: attr(data-label);
justify-self: start;
text-align: left;
width: auto;
font-size: 0.62rem;
font-weight: 650;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--muted);
line-height: 1.2;
padding-top: 0.06rem;
}
.cluster-k8s-table tbody td:not([data-label])::before {
content: none;
}
/* Документация: широкие таблицы Markdown → мини-карточки (класс и data-label в documentation.js) */
.readme-section-card.markdown-body table.markdown-body-table--stack {
display: block;
width: 100%;
min-width: 0;
border-collapse: separate;
border-spacing: 0;
margin: 0.5rem 0;
}
.readme-section-card.markdown-body table.markdown-body-table--stack thead {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.readme-section-card.markdown-body table.markdown-body-table--stack tbody {
display: block;
}
.readme-section-card.markdown-body table.markdown-body-table--stack tbody tr {
display: block;
margin-bottom: 0.6rem;
padding: 0.5rem 0.6rem;
border: 1px solid var(--border);
border-radius: 10px;
background: rgba(0, 0, 0, 0.08);
box-sizing: border-box;
}
html[data-theme="light"]
.readme-section-card.markdown-body
table.markdown-body-table--stack
tbody
tr {
background: rgba(59, 130, 246, 0.04);
}
.readme-section-card.markdown-body table.markdown-body-table--stack tbody td {
display: grid;
grid-template-columns: minmax(5rem, 38%) minmax(0, 1fr);
gap: 0.28rem 0.4rem;
align-items: center;
justify-items: start;
border: none;
border-bottom: 1px solid var(--border);
padding: 0.38rem 0;
word-break: break-word;
overflow-wrap: anywhere;
text-align: center;
}
.readme-section-card.markdown-body table.markdown-body-table--stack tbody td > * {
justify-self: center;
text-align: center;
}
.readme-section-card.markdown-body table.markdown-body-table--stack tbody td .badge {
width: fit-content;
max-width: 100%;
box-sizing: border-box;
}
.readme-section-card.markdown-body table.markdown-body-table--stack tbody tr td:last-child {
border-bottom: none;
}
.readme-section-card.markdown-body table.markdown-body-table--stack tbody td::before {
content: attr(data-label);
justify-self: start;
text-align: left;
width: auto;
font-size: 0.62rem;
font-weight: 650;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--muted);
}
.readme-section-card.markdown-body table.markdown-body-table--stack tbody td:not([data-label])::before {
content: none;
}
}