mirror of
https://github.com/infinition/Bjorn.git
synced 2026-03-16 01:01:58 +00:00
Add Loki and Sentinel utility classes for web API endpoints
- Implemented LokiUtils class with GET and POST endpoints for managing scripts, jobs, and payloads. - Added SentinelUtils class with GET and POST endpoints for managing events, rules, devices, and notifications. - Both classes include error handling and JSON response formatting.
This commit is contained in:
10665
web/css/pages.css
10665
web/css/pages.css
File diff suppressed because it is too large
Load Diff
153
web/css/pages/actions-studio.css
Normal file
153
web/css/pages/actions-studio.css
Normal file
@@ -0,0 +1,153 @@
|
||||
/* ===== STUDIO RUNTIME HOST ===== */
|
||||
.studio-container.studio-runtime-host {
|
||||
min-height: calc(100vh - var(--h-topbar, 56px) - var(--h-bottombar, 60px) - 12px);
|
||||
height: calc(100vh - var(--h-topbar, 56px) - var(--h-bottombar, 60px) - 12px);
|
||||
}
|
||||
|
||||
.studio-container.studio-runtime-host #app {
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
display: grid;
|
||||
grid-template-rows: auto minmax(0, 1fr) auto;
|
||||
}
|
||||
|
||||
.studio-container.studio-runtime-host main {
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.studio-container.studio-runtime-host #left,
|
||||
.studio-container.studio-runtime-host #center,
|
||||
.studio-container.studio-runtime-host #right {
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* ===== Studio kebab menu (replaces inline styles) ===== */
|
||||
.studio-container .kebab {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.studio-container .studio-kebab-menu {
|
||||
position: absolute;
|
||||
top: calc(100% + 6px);
|
||||
right: 0;
|
||||
min-width: 240px;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 12px;
|
||||
padding: 6px;
|
||||
box-shadow: 0 10px 32px rgba(0, 0, 0, .45);
|
||||
display: none;
|
||||
z-index: 2400;
|
||||
}
|
||||
|
||||
.studio-container .studio-kebab-menu .item {
|
||||
padding: .55rem .7rem;
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
color: var(--ink);
|
||||
transition: background .15s ease;
|
||||
}
|
||||
|
||||
.studio-container .studio-kebab-menu .item:hover {
|
||||
background: color-mix(in oklab, var(--ink) 8%, transparent);
|
||||
}
|
||||
|
||||
/* ===== Studio legend dots ===== */
|
||||
.studio-container .legend-dot {
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.studio-container .legend-dot.legend-ok {
|
||||
background: var(--ok, #22c55e);
|
||||
}
|
||||
|
||||
.studio-container .legend-dot.legend-bad {
|
||||
background: var(--bad, #ef4444);
|
||||
}
|
||||
|
||||
.studio-container .legend-dot.legend-req {
|
||||
background: #7aa7ff;
|
||||
}
|
||||
|
||||
/* ===== Studio create host button ===== */
|
||||
.studio-container .studio-create-host-btn {
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* ===== Studio action buttons row ===== */
|
||||
.studio-container .studio-action-btns {
|
||||
margin-top: .6rem;
|
||||
}
|
||||
|
||||
/* ===== Studio mono input ===== */
|
||||
.studio-container .mono-input {
|
||||
font-family: ui-monospace, 'Cascadia Code', 'Fira Code', monospace;
|
||||
}
|
||||
|
||||
/* ===== Flex-1 utility ===== */
|
||||
.studio-container .flex-1 {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* ===== Studio link wizard endpoints ===== */
|
||||
.studio-container .studio-link-endpoints {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
/* ===== Studio preview row ===== */
|
||||
.studio-container .studio-preview-row {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* ===== Studio wizard buttons ===== */
|
||||
.studio-container .studio-wizard-btns {
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.studio-container.studio-runtime-host #left,
|
||||
.studio-container.studio-runtime-host #right {
|
||||
top: calc(var(--h-topbar, 56px) + var(--studio-header-h, 52px) + 8px);
|
||||
}
|
||||
}
|
||||
|
||||
.studio-container .studio-loading {
|
||||
padding: 14px;
|
||||
color: var(--muted);
|
||||
text-align: center;
|
||||
border: 1px dashed var(--c-border);
|
||||
border-radius: 10px;
|
||||
margin: 12px;
|
||||
}
|
||||
|
||||
/* ===== Backup page responsive ===== */
|
||||
@media (max-width: 900px) {
|
||||
.page-backup .backup-layout {
|
||||
grid-template-columns: 1fr;
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.page-backup .backup-sidebar {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
.page-backup .backup-sidehead {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.page-backup.page-with-sidebar .backup-sidebar {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
.page-backup.page-with-sidebar .backup-sidehead {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
}
|
||||
993
web/css/pages/attacks.css
Normal file
993
web/css/pages/attacks.css
Normal file
@@ -0,0 +1,993 @@
|
||||
/* ==========================================================================
|
||||
ATTACKS — Full page: Attacks · Comments · Images · EPD Layout
|
||||
Expert UX/UI — responsive, no unwanted scroll, clean layouts.
|
||||
========================================================================== */
|
||||
|
||||
/* ── Sidebar scroll isolation ──────────────────────────────── */
|
||||
.attacks-container .attacks-sidebar.page-sidebar {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ── Main area: fill height so textarea stretches ─────────── */
|
||||
.attacks-container .attacks-main.page-main {
|
||||
max-height: calc(100vh - var(--h-topbar, 56px) - var(--h-bottombar, 56px) - 24px);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ── Tabs ─────────────────────────────────────────────────── */
|
||||
.attacks-container .tabs-container {
|
||||
display: flex;
|
||||
gap: 3px;
|
||||
padding: 0 0 8px;
|
||||
border-bottom: 1px solid var(--_border);
|
||||
}
|
||||
|
||||
.attacks-container .attacks-sidebar > .tabs-container {
|
||||
margin: 10px 10px 0;
|
||||
padding-bottom: 6px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Keep sidehead + tabs pinned at top of sidebar */
|
||||
.attacks-container .attacks-sidebar > .sidehead {
|
||||
flex-shrink: 0;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 5;
|
||||
background: var(--grad-card);
|
||||
}
|
||||
|
||||
.attacks-container .attacks-sidebar > .sidebar-page {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 8px 10px 10px;
|
||||
}
|
||||
|
||||
.attacks-container .tab-btn {
|
||||
flex: 1;
|
||||
padding: 8px 4px;
|
||||
border: 1px solid var(--_border);
|
||||
border-bottom: none;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
letter-spacing: .02em;
|
||||
border-radius: 8px 8px 0 0;
|
||||
color: var(--_muted);
|
||||
background: transparent;
|
||||
transition: color .15s, background .15s;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.attacks-container .tab-btn:hover {
|
||||
color: var(--_ink);
|
||||
background: var(--_panel-lo);
|
||||
}
|
||||
|
||||
.attacks-container .tab-btn.active {
|
||||
color: var(--_ink);
|
||||
background: color-mix(in oklab, var(--_acid2) 10%, var(--_panel-lo));
|
||||
border-color: color-mix(in oklab, var(--_acid2) 25%, var(--_border));
|
||||
}
|
||||
|
||||
/* ── Unified list (shared across sidebar tabs) ────────────── */
|
||||
.attacks-container .unified-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.attacks-container .unified-list .card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px;
|
||||
margin-bottom: 4px;
|
||||
cursor: pointer;
|
||||
border-radius: 10px;
|
||||
background: var(--_panel-lo);
|
||||
transition: background .15s;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.attacks-container .unified-list .card:hover {
|
||||
background: var(--_panel-hi);
|
||||
}
|
||||
|
||||
.attacks-container .unified-list .card.selected {
|
||||
background: color-mix(in oklab, var(--_acid2) 12%, var(--_panel-hi));
|
||||
border-color: color-mix(in oklab, var(--_acid2) 30%, var(--_border));
|
||||
}
|
||||
|
||||
.attacks-container .unified-list .card img {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border-radius: 8px;
|
||||
object-fit: cover;
|
||||
background: #0b0e13;
|
||||
border: 1px solid var(--_border);
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.attacks-container .unified-list .card span {
|
||||
flex: 1;
|
||||
font-weight: 700;
|
||||
font-size: 13px;
|
||||
color: var(--_ink);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ── Enable dot ───────────────────────────────────────────── */
|
||||
.attacks-container .enable-dot {
|
||||
--size: 12px;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--_border);
|
||||
background: var(--ko);
|
||||
box-shadow: 0 0 0 0 var(--ko-glow);
|
||||
transition: .18s ease;
|
||||
flex: 0 0 auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.attacks-container .enable-dot.on {
|
||||
background: var(--ok);
|
||||
box-shadow: 0 0 0 3px var(--ok-glow);
|
||||
border-color: color-mix(in oklab, var(--ok) 45%, var(--_border));
|
||||
}
|
||||
|
||||
.attacks-container .enable-dot:focus-visible {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px color-mix(in oklab, var(--_acid2) 45%, transparent);
|
||||
}
|
||||
|
||||
/* ── Page content panels ──────────────────────────────────── */
|
||||
.attacks-container .page-content {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.attacks-container .page-content.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* Suppress focus ring on main area (used for arrow key nav in EPD editor) */
|
||||
.attacks-container .page-content:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* ── ATTACKS TAB: Editor ──────────────────────────────────── */
|
||||
.attacks-container .editor-textarea-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
gap: 10px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.attacks-container .editor-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.attacks-container .editor-header h2 {
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.attacks-container .editor-buttons {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.attacks-container .editor-textarea {
|
||||
flex: 1;
|
||||
min-height: 200px;
|
||||
resize: vertical;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
color: var(--_ink);
|
||||
background: var(--_panel-lo);
|
||||
border: 1px solid var(--_border);
|
||||
border-radius: 10px;
|
||||
padding: 12px;
|
||||
transition: border-color .15s;
|
||||
}
|
||||
|
||||
.attacks-container .editor-textarea:focus {
|
||||
outline: none;
|
||||
border-color: color-mix(in oklab, var(--_acid2) 28%, var(--_border));
|
||||
box-shadow: 0 0 0 2px color-mix(in oklab, var(--_acid2) 12%, transparent);
|
||||
background: var(--_panel-hi);
|
||||
}
|
||||
|
||||
/* ── IMAGES TAB: Actions bar + grid ───────────────────────── */
|
||||
.attacks-container .actions-bar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
background: var(--_panel);
|
||||
padding: 8px 10px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid var(--_border);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.attacks-container .actions-bar button,
|
||||
.attacks-container .chip,
|
||||
.attacks-container .select,
|
||||
.attacks-container .sort-toggle {
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--_border);
|
||||
color: var(--_ink);
|
||||
background: var(--_panel-lo);
|
||||
padding: 7px 10px;
|
||||
cursor: pointer;
|
||||
transition: .15s;
|
||||
font-weight: 700;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.attacks-container .actions-bar button:hover,
|
||||
.attacks-container .chip:hover,
|
||||
.attacks-container .select:hover,
|
||||
.attacks-container .sort-toggle:hover {
|
||||
background: var(--_panel-hi);
|
||||
}
|
||||
|
||||
.attacks-container .actions-bar button.danger {
|
||||
background: color-mix(in oklab, var(--_acid) 10%, var(--_panel-lo));
|
||||
}
|
||||
|
||||
.attacks-container .actions-bar button.danger:hover {
|
||||
background: color-mix(in oklab, var(--_acid) 16%, var(--_panel-hi));
|
||||
}
|
||||
|
||||
.attacks-container .chip { border-radius: 999px; }
|
||||
.attacks-container .select { appearance: none; }
|
||||
.attacks-container .sort-toggle { min-width: 36px; text-align: center; }
|
||||
|
||||
.attacks-container .field {
|
||||
position: relative;
|
||||
min-width: 140px;
|
||||
flex: 1 1 140px;
|
||||
max-width: 240px;
|
||||
}
|
||||
|
||||
.attacks-container .input {
|
||||
width: 100%;
|
||||
padding: 7px 10px 7px 32px;
|
||||
color: var(--_ink);
|
||||
background: var(--_panel-lo);
|
||||
border: 1px solid var(--_border);
|
||||
border-radius: 8px;
|
||||
outline: none;
|
||||
font-size: 12px;
|
||||
transition: .15s;
|
||||
}
|
||||
|
||||
.attacks-container .input:focus {
|
||||
border-color: color-mix(in oklab, var(--_acid2) 28%, var(--_border));
|
||||
box-shadow: 0 0 0 2px color-mix(in oklab, var(--_acid2) 12%, transparent);
|
||||
background: var(--_panel-hi);
|
||||
}
|
||||
|
||||
.attacks-container .field .icon {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 7px;
|
||||
opacity: .6;
|
||||
pointer-events: none;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.attacks-container .range-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.attacks-container .range { accent-color: var(--_acid); }
|
||||
|
||||
.attacks-container .image-container {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(var(--tile-min), 1fr));
|
||||
padding-bottom: 80px;
|
||||
}
|
||||
|
||||
.attacks-container .image-item {
|
||||
position: relative;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
aspect-ratio: 1/1;
|
||||
transition: .15s;
|
||||
background: var(--_panel-lo);
|
||||
border: 1px solid var(--_border);
|
||||
}
|
||||
|
||||
.attacks-container .image-item:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--_shadow);
|
||||
}
|
||||
|
||||
.attacks-container .image-item img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
object-fit: contain;
|
||||
background: #0b0e13;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
.attacks-container .image-info {
|
||||
position: absolute;
|
||||
inset: auto 0 0 0;
|
||||
padding: 4px 6px;
|
||||
text-align: center;
|
||||
font-size: 11px;
|
||||
color: var(--_ink);
|
||||
background: linear-gradient(180deg, transparent, rgba(0, 0, 0, .7));
|
||||
}
|
||||
|
||||
.attacks-container .select-ring {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
border: 3px solid transparent;
|
||||
border-radius: 10px;
|
||||
transition: .15s;
|
||||
}
|
||||
|
||||
.attacks-container .image-item.selectable:hover .select-ring {
|
||||
border-color: color-mix(in oklab, var(--_acid2) 35%, transparent);
|
||||
}
|
||||
|
||||
.attacks-container .image-item.selected .select-ring {
|
||||
border-color: var(--_acid2);
|
||||
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--_acid2) 30%, transparent);
|
||||
}
|
||||
|
||||
.attacks-container .tick-overlay {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 6px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 50%;
|
||||
background: color-mix(in oklab, var(--_acid) 80%, white);
|
||||
color: #001;
|
||||
font-weight: 900;
|
||||
font-size: 12px;
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: var(--_shadow);
|
||||
}
|
||||
|
||||
.attacks-container .image-item.selected .tick-overlay {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.attacks-container .skeleton {
|
||||
border-radius: 10px;
|
||||
aspect-ratio: 1/1;
|
||||
background: linear-gradient(90deg, rgba(255, 255, 255, .03) 25%, rgba(255, 255, 255, .07) 37%, rgba(255, 255, 255, .03) 63%);
|
||||
background-size: 400% 100%;
|
||||
animation: atk-shimmer 1.1s infinite;
|
||||
border: 1px solid var(--_border);
|
||||
}
|
||||
|
||||
@keyframes atk-shimmer {
|
||||
0% { background-position: 100% 0; }
|
||||
100% { background-position: 0 0; }
|
||||
}
|
||||
|
||||
/* ── Mode visibility toggles ─────────────────────────────── */
|
||||
.attacks-container .edit-only { display: none; }
|
||||
.attacks-container .status-only { display: none; }
|
||||
.attacks-container .static-only { display: none; }
|
||||
.attacks-container .web-only { display: none; }
|
||||
.attacks-container .icons-only { display: none; }
|
||||
|
||||
.attacks-container .edit-mode .edit-only { display: inline-flex; }
|
||||
.attacks-container .status-mode .status-only { display: inline-block; }
|
||||
.attacks-container .static-mode .static-only { display: inline-block; }
|
||||
.attacks-container .web-mode .web-only { display: inline-block; }
|
||||
.attacks-container .icons-mode .icons-only { display: inline-block; }
|
||||
|
||||
/* ── COMMENTS TAB ─────────────────────────────────────────── */
|
||||
.attacks-container .buttons-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
flex-wrap: wrap;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
background: var(--_panel);
|
||||
padding: 6px 8px;
|
||||
border-radius: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.attacks-container .buttons-container h2 {
|
||||
margin: 0;
|
||||
margin-right: auto;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.attacks-container .comments-container {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.attacks-container .comments-editor {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
white-space: pre;
|
||||
word-wrap: normal;
|
||||
background: var(--_panel-lo);
|
||||
color: var(--_ink);
|
||||
border: 1px solid var(--_border);
|
||||
border-radius: 10px;
|
||||
padding: 14px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.attacks-container .comments-editor:focus {
|
||||
outline: none;
|
||||
border-color: color-mix(in oklab, var(--_acid2) 28%, var(--_border));
|
||||
box-shadow: 0 0 0 2px color-mix(in oklab, var(--_acid2) 12%, transparent);
|
||||
background: var(--_panel-hi);
|
||||
}
|
||||
|
||||
.attacks-container .comments-editor.placeholder { color: var(--_muted); }
|
||||
.attacks-container .comment-line { display: block; width: 100%; }
|
||||
.attacks-container .comment-line:nth-child(odd) { color: var(--_ink); }
|
||||
.attacks-container .comment-line:nth-child(even) { color: var(--_acid); }
|
||||
|
||||
/* ── Modals (shared) ──────────────────────────────────────── */
|
||||
.attacks-container .modal-action {
|
||||
display: none;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1000;
|
||||
padding: 10px;
|
||||
background: rgba(0, 0, 0, .6);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.attacks-container .modal-content {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 520px;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
background: var(--_panel-hi);
|
||||
padding: 20px;
|
||||
border-radius: 14px;
|
||||
border: 1px solid var(--_border);
|
||||
box-shadow: var(--_shadow);
|
||||
}
|
||||
|
||||
.attacks-container .modal-header h3 { margin: 0 0 10px; color: var(--_ink); }
|
||||
.attacks-container .modal-body { margin-bottom: 16px; }
|
||||
.attacks-container .modal-footer { display: flex; justify-content: flex-end; gap: 8px; }
|
||||
|
||||
.attacks-container .close {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
color: var(--_muted);
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.attacks-container .form-group { margin-bottom: 14px; }
|
||||
.attacks-container .form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
color: var(--_muted);
|
||||
font-weight: 700;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.attacks-container .form-group input[type="text"],
|
||||
.attacks-container .form-group input[type="number"],
|
||||
.attacks-container .form-group input[type="file"] {
|
||||
width: 100%;
|
||||
padding: 8px 10px;
|
||||
color: var(--_ink);
|
||||
background: var(--_panel-lo);
|
||||
border: 1px solid var(--_border);
|
||||
border-radius: 8px;
|
||||
outline: none;
|
||||
font-size: 13px;
|
||||
transition: .15s;
|
||||
}
|
||||
|
||||
.attacks-container .form-group input:focus {
|
||||
border-color: color-mix(in oklab, var(--_acid2) 28%, var(--_border));
|
||||
box-shadow: 0 0 0 2px color-mix(in oklab, var(--_acid2) 12%, transparent);
|
||||
background: var(--_panel-hi);
|
||||
}
|
||||
|
||||
/* ── Sidebar action buttons / hero buttons ────────────────── */
|
||||
.attacks-container .action-btn-container {
|
||||
padding: 2px;
|
||||
gap: 2px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.attacks-container .hero-btn {
|
||||
border-radius: 12px;
|
||||
background: var(--grid), var(--grad-hero);
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
border: 1px solid var(--c-border);
|
||||
box-shadow: var(--shadow);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
text-align: center;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
/* ── Responsive: mobile main area ─────────────────────────── */
|
||||
@media (max-width: 900px) {
|
||||
.attacks-container .attacks-main.page-main {
|
||||
max-height: calc(100vh - var(--h-topbar, 56px) - var(--h-bottombar, 56px) - 12px);
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Responsive: base (all tabs) ──────────────────────────── */
|
||||
@media (max-width: 480px) {
|
||||
.attacks-container .tabs-container { gap: 2px; }
|
||||
|
||||
.attacks-container .tab-btn {
|
||||
font-size: 11px;
|
||||
padding: 6px 3px;
|
||||
}
|
||||
|
||||
.attacks-container .actions-bar {
|
||||
gap: 6px;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.attacks-container .actions-bar button,
|
||||
.attacks-container .chip,
|
||||
.attacks-container .select {
|
||||
padding: 6px 8px;
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ==========================================================================
|
||||
EPD LAYOUT EDITOR
|
||||
========================================================================== */
|
||||
|
||||
/* ── Toolbar — two compact rows ───────────────────────────── */
|
||||
.epd-editor-toolbar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
margin-bottom: 10px;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
background: var(--_panel);
|
||||
padding: 8px 10px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid var(--_border);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.epd-toolbar-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.epd-editor-toolbar .select,
|
||||
.epd-editor-toolbar .btn {
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--_border);
|
||||
color: var(--_ink);
|
||||
background: var(--_panel-lo);
|
||||
padding: 5px 9px;
|
||||
cursor: pointer;
|
||||
transition: .15s;
|
||||
font-weight: 700;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.epd-editor-toolbar .select { appearance: none; }
|
||||
|
||||
.epd-editor-toolbar .btn:hover,
|
||||
.epd-editor-toolbar .select:hover {
|
||||
background: var(--_panel-hi);
|
||||
}
|
||||
|
||||
.epd-editor-toolbar .btn.active {
|
||||
background: color-mix(in oklab, var(--_acid2) 14%, var(--_panel-lo));
|
||||
border-color: color-mix(in oklab, var(--_acid2) 25%, var(--_border));
|
||||
}
|
||||
|
||||
.epd-editor-toolbar .btn.danger {
|
||||
background: color-mix(in oklab, var(--_acid) 10%, var(--_panel-lo));
|
||||
}
|
||||
|
||||
.epd-editor-toolbar .btn.danger:hover {
|
||||
background: color-mix(in oklab, var(--_acid) 16%, var(--_panel-hi));
|
||||
}
|
||||
|
||||
/* ── Zoom ─────────────────────────────────────────────────── */
|
||||
.epd-zoom-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.epd-zoom-range {
|
||||
width: 70px;
|
||||
accent-color: var(--_acid);
|
||||
}
|
||||
|
||||
.epd-zoom-label {
|
||||
min-width: 32px;
|
||||
text-align: right;
|
||||
opacity: .65;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* ── Content row: canvas + live preview ───────────────────── */
|
||||
.epd-content-row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: flex-start;
|
||||
min-height: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* ── Canvas wrapper — scrolls internally, never causes page scroll */
|
||||
.epd-canvas-wrapper {
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
max-height: calc(100vh - var(--h-topbar, 56px) - var(--h-bottombar, 56px) - 140px);
|
||||
overflow: auto;
|
||||
border-radius: 10px;
|
||||
border: 1px solid var(--_border);
|
||||
padding: 12px;
|
||||
/* Checkerboard transparency */
|
||||
background-image:
|
||||
linear-gradient(45deg, #e0e0e0 25%, transparent 25%),
|
||||
linear-gradient(-45deg, #e0e0e0 25%, transparent 25%),
|
||||
linear-gradient(45deg, transparent 75%, #e0e0e0 75%),
|
||||
linear-gradient(-45deg, transparent 75%, #e0e0e0 75%);
|
||||
background-size: 14px 14px;
|
||||
background-position: 0 0, 0 7px, 7px -7px, -7px 0;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.epd-canvas-wrapper.mode-bn {
|
||||
background-image:
|
||||
linear-gradient(45deg, #1a1a1a 25%, transparent 25%),
|
||||
linear-gradient(-45deg, #1a1a1a 25%, transparent 25%),
|
||||
linear-gradient(45deg, transparent 75%, #1a1a1a 75%),
|
||||
linear-gradient(-45deg, transparent 75%, #1a1a1a 75%);
|
||||
background-color: #111;
|
||||
}
|
||||
|
||||
/* Inverted mode — handled at SVG level (bg fill + image filter) */
|
||||
|
||||
.epd-canvas-wrapper svg {
|
||||
display: block;
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.epd-canvas-wrapper svg g[data-key] { cursor: move; }
|
||||
.epd-canvas-wrapper svg g[data-key] rect { transition: stroke-width .1s; }
|
||||
.epd-canvas-wrapper svg g[data-key]:hover rect { stroke-width: 1.2; }
|
||||
|
||||
/* ── Live EPD preview ─────────────────────────────────────── */
|
||||
.epd-live-panel {
|
||||
flex: 0 0 auto;
|
||||
width: 180px;
|
||||
background: var(--_panel-lo);
|
||||
border: 1px solid var(--_border);
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.epd-live-panel h4 {
|
||||
margin: 0 0 6px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: var(--_ink);
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.epd-live-img {
|
||||
width: 100%;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--_border);
|
||||
background: #0b0e13;
|
||||
image-rendering: pixelated;
|
||||
transition: opacity .3s;
|
||||
}
|
||||
|
||||
/* ── Sidebar: properties panel ────────────────────────────── */
|
||||
.epd-props-panel {
|
||||
padding: 0 0 8px;
|
||||
border-bottom: 1px solid var(--_border);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.epd-props-panel h4 {
|
||||
margin: 0 0 6px;
|
||||
font-size: 14px;
|
||||
color: var(--_acid2);
|
||||
}
|
||||
|
||||
.epd-hint {
|
||||
opacity: .55;
|
||||
font-size: 12px;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.epd-prop-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.epd-prop-row label {
|
||||
font-weight: 700;
|
||||
font-size: 12px;
|
||||
min-width: 20px;
|
||||
color: var(--_muted);
|
||||
}
|
||||
|
||||
.epd-prop-input {
|
||||
width: 60px;
|
||||
padding: 4px 6px;
|
||||
font-size: 12px;
|
||||
color: var(--_ink);
|
||||
background: var(--_panel-lo);
|
||||
border: 1px solid var(--_border);
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
transition: .15s;
|
||||
}
|
||||
|
||||
.epd-prop-input:focus {
|
||||
border-color: color-mix(in oklab, var(--_acid2) 28%, var(--_border));
|
||||
box-shadow: 0 0 0 2px color-mix(in oklab, var(--_acid2) 12%, transparent);
|
||||
}
|
||||
|
||||
.epd-delete-btn {
|
||||
margin-top: 6px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* ── Sidebar: element list ────────────────────────────────── */
|
||||
.epd-elements-list {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.epd-elements-list h4 {
|
||||
margin: 8px 0 4px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.epd-elements-list .unified-list {
|
||||
max-height: none;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.epd-element-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 5px 8px;
|
||||
margin-bottom: 2px;
|
||||
cursor: pointer;
|
||||
border-radius: 8px;
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
transition: background .12s;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.epd-element-item:hover {
|
||||
background: var(--_panel-lo);
|
||||
}
|
||||
|
||||
.epd-element-item.selected {
|
||||
background: color-mix(in oklab, var(--_acid2) 12%, var(--_panel-hi));
|
||||
border-color: color-mix(in oklab, var(--_acid2) 25%, var(--_border));
|
||||
}
|
||||
|
||||
.epd-type-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.epd-list-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
object-fit: contain;
|
||||
image-rendering: pixelated;
|
||||
border-radius: 2px;
|
||||
flex: 0 0 auto;
|
||||
background: #0b0e13;
|
||||
}
|
||||
|
||||
.epd-line-dash {
|
||||
font-weight: 900;
|
||||
opacity: .4;
|
||||
min-width: 14px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.epd-coords {
|
||||
font-size: 10px;
|
||||
opacity: .4;
|
||||
font-family: monospace;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.epd-list-divider {
|
||||
padding: 4px 8px;
|
||||
font-size: 10px;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
opacity: .4;
|
||||
letter-spacing: .06em;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
/* ── Sidebar: font sizes ──────────────────────────────────── */
|
||||
.epd-fonts-section {
|
||||
border-top: 1px solid var(--_border);
|
||||
padding-top: 6px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.epd-fonts-section h4 {
|
||||
margin: 0 0 4px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.epd-fonts-section .epd-prop-row label {
|
||||
min-width: 80px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.epd-meta-info { opacity: .4; font-size: 10px; }
|
||||
|
||||
/* ── Add element modal ────────────────────────────────────── */
|
||||
.epd-add-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1000;
|
||||
padding: 10px;
|
||||
background: rgba(0, 0, 0, .6);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.epd-add-modal .modal-content {
|
||||
width: 100%;
|
||||
max-width: 360px;
|
||||
background: var(--_panel-hi);
|
||||
padding: 18px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--_border);
|
||||
box-shadow: var(--_shadow);
|
||||
}
|
||||
|
||||
.epd-add-modal .form-group { margin-bottom: 10px; }
|
||||
|
||||
.epd-add-modal .form-group label {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
color: var(--_muted);
|
||||
font-weight: 700;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.epd-add-modal .modal-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 6px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
/* ── Responsive: EPD ──────────────────────────────────────── */
|
||||
@media (max-width: 900px) {
|
||||
.epd-content-row {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.epd-live-panel {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
position: static;
|
||||
}
|
||||
|
||||
.epd-canvas-wrapper {
|
||||
max-height: 65vh;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.epd-editor-toolbar {
|
||||
gap: 3px;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.epd-toolbar-row { gap: 4px; }
|
||||
|
||||
.epd-editor-toolbar .select,
|
||||
.epd-editor-toolbar .btn {
|
||||
padding: 4px 7px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.epd-zoom-range { width: 50px; }
|
||||
.epd-canvas-wrapper { padding: 6px; max-height: 55vh; }
|
||||
.epd-live-panel { padding: 6px; }
|
||||
}
|
||||
274
web/css/pages/backup.css
Normal file
274
web/css/pages/backup.css
Normal file
@@ -0,0 +1,274 @@
|
||||
/* ===== BACKUP PAGE (NEW SPA LAYOUT) ===== */
|
||||
.page-backup {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.page-backup {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.page-backup .backup-sidebar,
|
||||
.page-backup .backup-main {
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 12px;
|
||||
background: var(--grad-card);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.page-backup .backup-sidebar {
|
||||
padding: 12px;
|
||||
display: grid;
|
||||
align-content: start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.page-backup .backup-sidehead {
|
||||
border-bottom: 1px dashed var(--c-border);
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.page-backup .backup-side-title {
|
||||
margin: 0;
|
||||
color: var(--acid);
|
||||
font-size: 14px;
|
||||
letter-spacing: .04em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.page-backup .backup-nav-item {
|
||||
width: 100%;
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 12px;
|
||||
background: color-mix(in oklab, var(--panel) 88%, transparent);
|
||||
color: var(--ink);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
transition: .18s;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.page-backup .backup-nav-item:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.page-backup .backup-nav-item.active {
|
||||
border-color: color-mix(in oklab, var(--acid) 45%, var(--c-border));
|
||||
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--acid-2) 30%, transparent);
|
||||
}
|
||||
|
||||
.page-backup .backup-nav-icon {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
object-fit: contain;
|
||||
border-radius: 8px;
|
||||
background: rgba(0, 0, 0, .2);
|
||||
}
|
||||
|
||||
.page-backup .backup-nav-label {
|
||||
font-weight: 700;
|
||||
letter-spacing: .01em;
|
||||
}
|
||||
|
||||
.page-backup .backup-main {
|
||||
padding: 14px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.page-backup .backup-title {
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
|
||||
.page-backup .backup-form {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.page-backup .backup-label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.page-backup .backup-form-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.page-backup .backup-input {
|
||||
flex: 1;
|
||||
min-width: 220px;
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 10px;
|
||||
background: var(--c-panel);
|
||||
color: var(--ink);
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.page-backup .backup-subtitle {
|
||||
margin: 10px 0;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .03em;
|
||||
}
|
||||
|
||||
.page-backup .backup-table-wrap {
|
||||
overflow: auto;
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.page-backup .backup-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.page-backup .backup-table th,
|
||||
.page-backup .backup-table td {
|
||||
padding: 10px;
|
||||
border-bottom: 1px dashed var(--c-border);
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.page-backup .backup-row-actions {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.page-backup .backup-default-pill {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.page-backup .backup-empty {
|
||||
padding: 22px;
|
||||
text-align: center;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.page-backup .backup-update-message {
|
||||
background: color-mix(in oklab, var(--ok) 18%, transparent);
|
||||
border: 1px solid color-mix(in oklab, var(--ok) 40%, var(--c-border));
|
||||
border-radius: 999px;
|
||||
padding: 10px 14px;
|
||||
display: inline-block;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.page-backup .backup-version-lines {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.page-backup .backup-update-available {
|
||||
color: var(--acid);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.page-backup .backup-update-ok {
|
||||
color: var(--ok);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.page-backup .backup-update-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.page-backup .backup-modal-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1200;
|
||||
background: rgba(0, 0, 0, .6);
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.page-backup .backup-modal {
|
||||
width: min(480px, 95vw);
|
||||
background: var(--grad-card);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 14px;
|
||||
padding: 12px;
|
||||
box-shadow: var(--shadow-hover);
|
||||
}
|
||||
|
||||
.page-backup .backup-modal-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.page-backup .backup-modal-title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.page-backup .backup-modal-help {
|
||||
color: var(--muted);
|
||||
margin: 8px 0 10px 0;
|
||||
}
|
||||
|
||||
.page-backup .backup-keep {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.page-backup .backup-modal-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
margin-top: 12px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px dashed var(--c-border);
|
||||
}
|
||||
|
||||
.page-backup .backup-loading-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1300;
|
||||
background: rgba(0, 0, 0, .6);
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.page-backup .backup-spinner {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
border: 4px solid transparent;
|
||||
border-top-color: var(--accent-2);
|
||||
border-right-color: var(--accent-2);
|
||||
border-radius: 50%;
|
||||
animation: bak-spin .9s linear infinite;
|
||||
}
|
||||
|
||||
/* Integrated layout provided by shared.css page-with-sidebar */
|
||||
.page-backup.page-with-sidebar {
|
||||
--page-sidebar-w: 280px;
|
||||
min-height: calc(100vh - var(--h-topbar, 56px) - var(--h-bottombar, 60px) - 24px);
|
||||
}
|
||||
|
||||
.page-backup.page-with-sidebar .backup-sidebar {
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.page-backup.page-with-sidebar .backup-main {
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
518
web/css/pages/bifrost.css
Normal file
518
web/css/pages/bifrost.css
Normal file
@@ -0,0 +1,518 @@
|
||||
/* ============================================================
|
||||
Bifrost (Pwnagotchi Mode) — SPA page styles
|
||||
============================================================ */
|
||||
|
||||
.bifrost-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
gap: 12px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
/* ── Header bar ─────────────────────────────────────────── */
|
||||
|
||||
.bifrost-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.bifrost-title {
|
||||
margin: 0;
|
||||
font-size: 1.3rem;
|
||||
font-weight: 800;
|
||||
color: var(--ink);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.bifrost-title-icon { font-size: 1.5rem; }
|
||||
|
||||
.bifrost-controls {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.bifrost-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 14px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--c-border);
|
||||
background: var(--c-panel);
|
||||
font-size: 0.8rem;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
cursor: pointer;
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.bifrost-btn.active {
|
||||
border-color: var(--acid);
|
||||
background: rgba(0, 255, 154, 0.08);
|
||||
color: var(--acid);
|
||||
box-shadow: 0 0 12px rgba(0, 255, 154, 0.15);
|
||||
}
|
||||
|
||||
.bifrost-btn .dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--muted-off, #555);
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.bifrost-btn.active .dot {
|
||||
background: var(--acid);
|
||||
box-shadow: 0 0 6px var(--acid);
|
||||
animation: bifrost-pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes bifrost-pulse {
|
||||
0%, 100% { opacity: 0.7; box-shadow: 0 0 4px var(--acid); }
|
||||
50% { opacity: 1; box-shadow: 0 0 12px var(--acid); }
|
||||
}
|
||||
|
||||
/* ── Stats bar ──────────────────────────────────────────── */
|
||||
|
||||
.bifrost-stats {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.bifrost-stat {
|
||||
flex: 1 1 100px;
|
||||
padding: 10px 14px;
|
||||
background: var(--grad-card);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.bifrost-stat-val {
|
||||
font-size: 1.4rem;
|
||||
font-weight: 800;
|
||||
font-family: 'Fira Code', monospace;
|
||||
color: var(--ink);
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.bifrost-stat-lbl {
|
||||
font-size: 0.65rem;
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* ── Main grid ──────────────────────────────────────────── */
|
||||
|
||||
.bifrost-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 340px;
|
||||
gap: 12px;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* ── Panels ─────────────────────────────────────────────── */
|
||||
|
||||
.bifrost-panel {
|
||||
background: var(--grad-card);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.bifrost-panel-head {
|
||||
padding: 10px 14px;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
border-bottom: 1px solid var(--c-border);
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* ── Face display ──────────────────────────────────────── */
|
||||
|
||||
.bifrost-live {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.bifrost-face-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 30px 20px 16px;
|
||||
gap: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.bifrost-face {
|
||||
font-family: 'Fira Code', 'Courier New', monospace;
|
||||
font-size: 2.8rem;
|
||||
font-weight: 700;
|
||||
color: var(--acid);
|
||||
text-shadow:
|
||||
0 0 10px rgba(0, 255, 154, 0.4),
|
||||
0 0 30px rgba(0, 255, 154, 0.15);
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
line-height: 1.2;
|
||||
user-select: none;
|
||||
transition: color 0.4s, text-shadow 0.4s;
|
||||
}
|
||||
|
||||
/* Mood-specific face colors */
|
||||
.bifrost-face.mood-excited {
|
||||
color: #00ff9a;
|
||||
text-shadow: 0 0 15px rgba(0, 255, 154, 0.6), 0 0 40px rgba(0, 255, 154, 0.25);
|
||||
}
|
||||
.bifrost-face.mood-happy { color: #00ff9a; }
|
||||
.bifrost-face.mood-grateful { color: #00dcff; text-shadow: 0 0 10px rgba(0, 220, 255, 0.4); }
|
||||
.bifrost-face.mood-bored { color: #ffd166; text-shadow: 0 0 10px rgba(255, 209, 102, 0.3); }
|
||||
.bifrost-face.mood-sad { color: #7ba5c9; text-shadow: 0 0 10px rgba(123, 165, 201, 0.3); }
|
||||
.bifrost-face.mood-angry { color: #ff3b3b; text-shadow: 0 0 10px rgba(255, 59, 59, 0.4); }
|
||||
.bifrost-face.mood-lonely { color: #b48cff; text-shadow: 0 0 10px rgba(180, 140, 255, 0.3); }
|
||||
.bifrost-face.mood-sleeping { color: var(--muted); text-shadow: none; }
|
||||
|
||||
/* Mood badge */
|
||||
.bifrost-mood {
|
||||
font-size: 0.72rem;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
padding: 3px 12px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.mood-badge-excited { background: rgba(0,255,154,0.15); color: #00ff9a; }
|
||||
.mood-badge-happy { background: rgba(0,255,154,0.12); color: #00ff9a; }
|
||||
.mood-badge-grateful { background: rgba(0,220,255,0.15); color: #00dcff; }
|
||||
.mood-badge-bored { background: rgba(255,209,102,0.15); color: #ffd166; }
|
||||
.mood-badge-sad { background: rgba(123,165,201,0.15); color: #7ba5c9; }
|
||||
.mood-badge-angry { background: rgba(255,59,59,0.15); color: #ff3b3b; }
|
||||
.mood-badge-lonely { background: rgba(180,140,255,0.15); color: #b48cff; }
|
||||
.mood-badge-sleeping { background: rgba(255,255,255,0.06); color: var(--muted); }
|
||||
.mood-badge-starting { background: rgba(255,255,255,0.06); color: var(--muted); }
|
||||
.mood-badge-ready { background: rgba(0,255,154,0.08); color: var(--acid); }
|
||||
|
||||
.bifrost-voice {
|
||||
font-size: 0.78rem;
|
||||
color: var(--muted);
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
max-width: 300px;
|
||||
line-height: 1.4;
|
||||
min-height: 1.4em;
|
||||
}
|
||||
|
||||
/* ── Info chips ────────────────────────────────────────── */
|
||||
|
||||
.bifrost-info-row {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
padding: 8px 14px;
|
||||
border-bottom: 1px solid var(--c-border);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.bifrost-info-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 2px 8px;
|
||||
background: rgba(0,0,0,0.2);
|
||||
border-radius: 6px;
|
||||
font-size: 0.7rem;
|
||||
font-family: 'Fira Code', monospace;
|
||||
}
|
||||
|
||||
.bifrost-info-chip.pwnd {
|
||||
background: rgba(0,255,154,0.1);
|
||||
border: 1px solid rgba(0,255,154,0.2);
|
||||
}
|
||||
|
||||
.bifrost-info-label {
|
||||
color: var(--muted);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.bifrost-info-value {
|
||||
color: var(--ink);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* ── Activity feed ─────────────────────────────────────── */
|
||||
|
||||
.bifrost-activity {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 8px 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.bifrost-activity-item {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 6px;
|
||||
padding: 3px 0;
|
||||
font-size: 0.73rem;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.03);
|
||||
}
|
||||
|
||||
.bifrost-act-time {
|
||||
color: var(--muted);
|
||||
font-family: 'Fira Code', monospace;
|
||||
font-size: 0.65rem;
|
||||
flex-shrink: 0;
|
||||
min-width: 28px;
|
||||
}
|
||||
|
||||
.bifrost-act-icon {
|
||||
flex-shrink: 0;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.bifrost-act-title {
|
||||
color: var(--ink);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.bifrost-act-detail {
|
||||
color: var(--muted);
|
||||
font-size: 0.68rem;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.bifrost-empty {
|
||||
color: var(--muted);
|
||||
text-align: center;
|
||||
padding: 30px 10px;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
/* ── Sidebar tabs ──────────────────────────────────────── */
|
||||
|
||||
.bifrost-side-tabs {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
padding: 6px;
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
border-bottom: 1px solid var(--c-border);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.bifrost-side-tab {
|
||||
flex: 1;
|
||||
padding: 5px 8px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
transition: 0.15s;
|
||||
}
|
||||
|
||||
.bifrost-side-tab.active {
|
||||
background: var(--c-panel);
|
||||
color: var(--acid);
|
||||
}
|
||||
|
||||
.bifrost-sidebar {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
/* ── Network rows ──────────────────────────────────────── */
|
||||
|
||||
.bifrost-net-row {
|
||||
padding: 6px 10px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--c-border);
|
||||
background: color-mix(in oklab, var(--c-panel) 60%, transparent);
|
||||
}
|
||||
|
||||
.bifrost-net-main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.bifrost-net-signal {
|
||||
font-size: 0.65rem;
|
||||
color: var(--acid);
|
||||
letter-spacing: -1px;
|
||||
flex-shrink: 0;
|
||||
min-width: 32px;
|
||||
}
|
||||
|
||||
.bifrost-net-essid {
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.bifrost-net-enc {
|
||||
font-size: 0.58rem;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
padding: 1px 5px;
|
||||
border-radius: 3px;
|
||||
letter-spacing: 0.5px;
|
||||
flex-shrink: 0;
|
||||
background: rgba(0,220,255,0.12);
|
||||
color: #00dcff;
|
||||
}
|
||||
|
||||
.bifrost-net-meta {
|
||||
font-size: 0.62rem;
|
||||
color: var(--muted);
|
||||
margin-top: 2px;
|
||||
font-family: 'Fira Code', monospace;
|
||||
}
|
||||
|
||||
/* ── Plugin rows ───────────────────────────────────────── */
|
||||
|
||||
.bifrost-plugin-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 10px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--c-border);
|
||||
background: color-mix(in oklab, var(--c-panel) 60%, transparent);
|
||||
}
|
||||
|
||||
.bifrost-plugin-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.bifrost-plugin-name {
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.bifrost-plugin-desc {
|
||||
font-size: 0.65rem;
|
||||
color: var(--muted);
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ── Epoch table ───────────────────────────────────────── */
|
||||
|
||||
.bifrost-epoch-table {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1px;
|
||||
font-size: 0.72rem;
|
||||
font-family: 'Fira Code', monospace;
|
||||
}
|
||||
|
||||
.bifrost-epoch-header,
|
||||
.bifrost-epoch-row {
|
||||
display: grid;
|
||||
grid-template-columns: 40px 35px 35px 35px 1fr 50px;
|
||||
gap: 4px;
|
||||
padding: 4px 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.bifrost-epoch-header {
|
||||
font-weight: 800;
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
font-size: 0.6rem;
|
||||
border-bottom: 1px solid var(--c-border);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: var(--c-panel);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.bifrost-epoch-row {
|
||||
border-bottom: 1px solid rgba(255,255,255,0.03);
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.bifrost-epoch-row:hover {
|
||||
background: rgba(255,255,255,0.03);
|
||||
}
|
||||
|
||||
/* ── Responsive ────────────────────────────────────────── */
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.bifrost-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.bifrost-stats {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.bifrost-stat {
|
||||
flex: 1 1 70px;
|
||||
min-width: 60px;
|
||||
padding: 8px 8px;
|
||||
}
|
||||
|
||||
.bifrost-stat-val { font-size: 1.1rem; }
|
||||
|
||||
.bifrost-page {
|
||||
padding: 10px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.bifrost-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.bifrost-face { font-size: 2rem; }
|
||||
.bifrost-face-wrap { padding: 20px 12px 12px; }
|
||||
}
|
||||
33
web/css/pages/bjorn.css
Normal file
33
web/css/pages/bjorn.css
Normal file
@@ -0,0 +1,33 @@
|
||||
/* ==========================================================================
|
||||
BJORN
|
||||
========================================================================== */
|
||||
.bjorn-container .image-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: calc(100vh - 70px);
|
||||
}
|
||||
|
||||
.bjorn-container .image-container img {
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
height: -webkit-fill-available;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.bjorn-container .image-container img:active {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.bjorn-container .image-container.fullscreen img {
|
||||
height: 100vh;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
@media (max-width:768px) {
|
||||
.bjorn-container .image-container {
|
||||
height: calc(100vh - 60px);
|
||||
}
|
||||
}
|
||||
|
||||
1814
web/css/pages/compat.css
Normal file
1814
web/css/pages/compat.css
Normal file
File diff suppressed because it is too large
Load Diff
370
web/css/pages/credentials.css
Normal file
370
web/css/pages/credentials.css
Normal file
@@ -0,0 +1,370 @@
|
||||
/* ===== CREDENTIALS ===== */
|
||||
.credentials-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
scroll-padding-top: 56px;
|
||||
}
|
||||
|
||||
.credentials-container .stats-bar {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
padding: 12px;
|
||||
background: color-mix(in oklab, var(--_panel) 88%, transparent);
|
||||
border: 1px solid var(--_border);
|
||||
border-radius: 12px;
|
||||
box-shadow: var(--_shadow);
|
||||
backdrop-filter: blur(16px);
|
||||
}
|
||||
|
||||
.credentials-container .stat-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--_border);
|
||||
border-radius: 10px;
|
||||
background: color-mix(in oklab, var(--_panel) 70%, transparent);
|
||||
}
|
||||
|
||||
.credentials-container .stat-icon {
|
||||
font-size: 1.1rem;
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
.credentials-container .stat-value {
|
||||
font-weight: 800;
|
||||
background: linear-gradient(135deg, var(--_acid), var(--_acid2));
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.credentials-container .stat-label {
|
||||
color: var(--_muted);
|
||||
font-size: .8rem;
|
||||
}
|
||||
|
||||
.credentials-container .global-search-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.credentials-container .global-search-input {
|
||||
width: 100%;
|
||||
padding: 10px 14px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--_border);
|
||||
background: color-mix(in oklab, var(--_panel) 90%, transparent);
|
||||
color: var(--_ink);
|
||||
}
|
||||
|
||||
.credentials-container .global-search-input:focus {
|
||||
outline: none;
|
||||
border-color: color-mix(in oklab, var(--_acid2) 40%, var(--_border));
|
||||
box-shadow: 0 0 0 3px color-mix(in oklab, var(--_acid2) 18%, transparent);
|
||||
}
|
||||
|
||||
.credentials-container .clear-global-button {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: none;
|
||||
border: 1px solid var(--_border);
|
||||
color: #ef4444;
|
||||
border-radius: 8px;
|
||||
padding: 2px 6px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.credentials-container .clear-global-button.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.credentials-container .tabs-container {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 20;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
min-height: 44px;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
background: color-mix(in oklab, var(--_panel) 92%, transparent);
|
||||
border: 1px solid var(--_border);
|
||||
border-radius: 12px;
|
||||
box-shadow: var(--_shadow);
|
||||
}
|
||||
|
||||
.credentials-container .tabs-container::-webkit-scrollbar {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.credentials-container .tab {
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
color: var(--_muted);
|
||||
font-weight: 700;
|
||||
font-size: .9rem;
|
||||
border: 1px solid transparent;
|
||||
white-space: nowrap;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.credentials-container .tab:hover {
|
||||
background: rgba(255, 255, 255, .05);
|
||||
color: var(--_ink);
|
||||
border-color: var(--_border);
|
||||
}
|
||||
|
||||
.credentials-container .tab.active {
|
||||
color: var(--_ink);
|
||||
background: linear-gradient(135deg, color-mix(in oklab, var(--_acid2) 18%, transparent), color-mix(in oklab, var(--_acid) 14%, transparent));
|
||||
border-color: color-mix(in oklab, var(--_acid2) 28%, var(--_border));
|
||||
}
|
||||
|
||||
.credentials-container .tab-badge {
|
||||
margin-left: 8px;
|
||||
padding: 2px 6px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, .1);
|
||||
border: 1px solid var(--_border);
|
||||
font-size: .75rem;
|
||||
}
|
||||
|
||||
.credentials-container .services-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.credentials-container .service-card {
|
||||
background: color-mix(in oklab, var(--_panel) 88%, transparent);
|
||||
border: 1px solid var(--_border);
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
box-shadow: var(--_shadow);
|
||||
}
|
||||
|
||||
.credentials-container .service-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
border-bottom: 1px solid color-mix(in oklab, var(--_border) 65%, transparent);
|
||||
}
|
||||
|
||||
.credentials-container .service-header:hover {
|
||||
background: rgba(255, 255, 255, .04);
|
||||
}
|
||||
|
||||
.credentials-container .service-title {
|
||||
flex: 1;
|
||||
font-weight: 800;
|
||||
letter-spacing: .2px;
|
||||
font-size: .95rem;
|
||||
text-transform: uppercase;
|
||||
background: linear-gradient(135deg, var(--_acid), var(--_acid2));
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.credentials-container .service-count {
|
||||
font-weight: 800;
|
||||
font-size: .8rem;
|
||||
padding: 4px 8px;
|
||||
border-radius: 10px;
|
||||
background: rgba(255, 255, 255, .08);
|
||||
color: var(--_ink);
|
||||
border: 1px solid var(--_border);
|
||||
}
|
||||
|
||||
.credentials-container .service-card[data-credentials]:not([data-credentials="0"]) .service-count {
|
||||
background: linear-gradient(135deg, #2e2e2e, #4CAF50);
|
||||
box-shadow: inset 0 0 0 1px rgba(76, 175, 80, .35);
|
||||
}
|
||||
|
||||
.credentials-container .search-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.credentials-container .search-input {
|
||||
padding: 6px 24px 6px 8px;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
background: rgba(255, 255, 255, .06);
|
||||
color: var(--_ink);
|
||||
font-size: .82rem;
|
||||
}
|
||||
|
||||
.credentials-container .search-input:focus {
|
||||
outline: none;
|
||||
background: rgba(255, 255, 255, .1);
|
||||
}
|
||||
|
||||
.credentials-container .clear-button {
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
border: none;
|
||||
background: none;
|
||||
color: #ef4444;
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.credentials-container .clear-button.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.credentials-container .download-button {
|
||||
border: 1px solid var(--_border);
|
||||
background: rgba(255, 255, 255, .04);
|
||||
color: var(--_muted);
|
||||
border-radius: 8px;
|
||||
padding: 4px 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.credentials-container .download-button:hover {
|
||||
color: #e99f00;
|
||||
filter: brightness(1.06);
|
||||
}
|
||||
|
||||
.credentials-container .collapse-indicator {
|
||||
color: var(--_muted);
|
||||
}
|
||||
|
||||
.credentials-container .service-card.collapsed .service-content {
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.credentials-container .service-content {
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.credentials-container .credential-item {
|
||||
border: 1px solid var(--_border);
|
||||
border-radius: 10px;
|
||||
margin-bottom: 6px;
|
||||
padding: 8px;
|
||||
background: rgba(255, 255, 255, .02);
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.credentials-container .credential-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.credentials-container .field-label {
|
||||
font-size: .78rem;
|
||||
color: var(--_muted);
|
||||
}
|
||||
|
||||
.credentials-container .field-value {
|
||||
flex: 1;
|
||||
padding: 2px 6px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.credentials-container .field-value:hover {
|
||||
background: rgba(255, 255, 255, .06);
|
||||
border-color: var(--_border);
|
||||
}
|
||||
|
||||
.credentials-container .bubble-blue {
|
||||
background: linear-gradient(135deg, #1d2a32, #00c4d6);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.credentials-container .bubble-green {
|
||||
background: linear-gradient(135deg, #1e2a24, #00b894);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.credentials-container .bubble-orange {
|
||||
background: linear-gradient(135deg, #3b2f1a, #e7951a);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.credentials-container .copied-feedback {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
bottom: 20px;
|
||||
transform: translateX(-50%);
|
||||
padding: 8px 12px;
|
||||
background: #4CAF50;
|
||||
color: #fff;
|
||||
border-radius: 10px;
|
||||
box-shadow: var(--_shadow);
|
||||
opacity: 0;
|
||||
transition: opacity .25s;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.credentials-container .copied-feedback.show {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* ── Mobile responsive ── */
|
||||
@media (max-width: 768px) {
|
||||
.credentials-container .stats-bar {
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.credentials-container .tabs-container {
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.credentials-container .tab {
|
||||
font-size: .75rem;
|
||||
padding: .35rem .6rem;
|
||||
}
|
||||
|
||||
.credentials-container .services-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.credentials-container .service-header {
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.credentials-container .search-container {
|
||||
width: 100%;
|
||||
order: 10;
|
||||
}
|
||||
|
||||
.credentials-container .credential-field {
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.credentials-container .field-value {
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
||||
660
web/css/pages/dashboard.css
Normal file
660
web/css/pages/dashboard.css
Normal file
@@ -0,0 +1,660 @@
|
||||
/* ===== MODERN DASHBOARD ===== */
|
||||
.dashboard-container.modern-dash {
|
||||
--pad: 12px;
|
||||
--gap: 12px;
|
||||
--card-bg: color-mix(in oklab, var(--_panel) 40%, transparent);
|
||||
--card-border: color-mix(in oklab, var(--_border) 80%, transparent);
|
||||
--card-radius: 16px;
|
||||
--anim-ease: cubic-bezier(0.2, 0.8, 0.2, 1);
|
||||
--accent: var(--_acid, #00ff9a);
|
||||
--glass: blur(12px);
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--gap);
|
||||
padding: 8px;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.dashboard-container.modern-dash {
|
||||
padding: 16px;
|
||||
--gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes slip-up {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(12px) scale(0.98);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.modern-dash .anim-enter {
|
||||
animation: slip-up 0.5s var(--anim-ease) both;
|
||||
}
|
||||
|
||||
.modern-dash .anim-enter:nth-child(1) {
|
||||
animation-delay: 0.0s;
|
||||
}
|
||||
|
||||
.modern-dash .anim-enter:nth-child(2) {
|
||||
animation-delay: 0.1s;
|
||||
}
|
||||
|
||||
.modern-dash .anim-enter:nth-child(3) {
|
||||
animation-delay: 0.15s;
|
||||
}
|
||||
|
||||
/* Top Bar */
|
||||
.modern-dash .top-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 4px 6px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.modern-dash .liveops {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
padding: 6px 12px;
|
||||
border-radius: 20px;
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--card-border);
|
||||
backdrop-filter: var(--glass);
|
||||
-webkit-backdrop-filter: var(--glass);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.2s ease;
|
||||
font-weight: 700;
|
||||
color: var(--_ink);
|
||||
}
|
||||
|
||||
.modern-dash .liveops:hover {
|
||||
background: color-mix(in oklab, var(--_panel) 70%, transparent);
|
||||
border-color: var(--accent);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.modern-dash .liveops-time {
|
||||
font-weight: 500;
|
||||
color: var(--_muted);
|
||||
}
|
||||
|
||||
.modern-dash .pulse-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--ok);
|
||||
box-shadow: 0 0 8px var(--ok);
|
||||
animation: pulse-dot-anim 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse-dot-anim {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: .5;
|
||||
transform: scale(1.3);
|
||||
}
|
||||
}
|
||||
|
||||
.modern-dash .sys-badges {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.modern-dash .badge {
|
||||
padding: 6px 10px;
|
||||
border-radius: 12px;
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--card-border);
|
||||
font-family: ui-monospace, monospace;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
color: var(--_ink);
|
||||
backdrop-filter: var(--glass);
|
||||
-webkit-backdrop-filter: var(--glass);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.modern-dash .mode-badge {
|
||||
color: var(--accent);
|
||||
border-color: color-mix(in oklab, var(--accent) 30%, transparent);
|
||||
}
|
||||
|
||||
/* Main layout grid */
|
||||
.modern-dash .dash-main {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--gap);
|
||||
}
|
||||
|
||||
@media(min-width: 900px) {
|
||||
.modern-dash .dash-main {
|
||||
grid-template-columns: 340px 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width: 1200px) {
|
||||
.modern-dash .dash-main {
|
||||
grid-template-columns: 380px 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.modern-dash .dash-col-left,
|
||||
.modern-dash .dash-col-right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--gap);
|
||||
}
|
||||
|
||||
/* Card Base */
|
||||
.modern-dash .dash-card {
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--card-border);
|
||||
border-radius: var(--card-radius);
|
||||
padding: var(--pad);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
backdrop-filter: var(--glass);
|
||||
-webkit-backdrop-filter: var(--glass);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.05);
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.modern-dash .dash-card:hover {
|
||||
border-color: color-mix(in oklab, var(--_border) 100%, transparent);
|
||||
}
|
||||
|
||||
/* Hero Card */
|
||||
.modern-dash .hero-card {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
padding: 16px;
|
||||
gap: 16px;
|
||||
background: linear-gradient(135deg, color-mix(in oklab, var(--_panel) 60%, transparent), color-mix(in oklab, var(--_panel) 20%, transparent));
|
||||
}
|
||||
|
||||
.modern-dash .hero-left {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.modern-dash .hero-divider {
|
||||
width: 1px;
|
||||
background: var(--card-border);
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.modern-dash .hero-right {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* Battery Widget */
|
||||
.modern-dash .battery-wrap {
|
||||
position: relative;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
@media(min-width: 400px) {
|
||||
.modern-dash .battery-wrap {
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
}
|
||||
}
|
||||
|
||||
.modern-dash .battery-ring {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transform: translate(-50%, -50%) rotate(-90deg);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.modern-dash .batt-bg {
|
||||
fill: none;
|
||||
stroke: color-mix(in oklab, var(--_ink) 10%, transparent);
|
||||
stroke-width: 13;
|
||||
opacity: .35;
|
||||
}
|
||||
|
||||
.modern-dash .batt-fg {
|
||||
fill: none;
|
||||
stroke: url(#batt-grad);
|
||||
stroke-width: 13;
|
||||
stroke-linecap: round;
|
||||
filter: url(#batt-glow);
|
||||
stroke-dasharray: 100;
|
||||
stroke-dashoffset: 100;
|
||||
transition: stroke-dashoffset 0.9s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.modern-dash .batt-scan {
|
||||
fill: none;
|
||||
stroke: var(--_acid2);
|
||||
stroke-width: 13;
|
||||
stroke-linecap: round;
|
||||
stroke-dasharray: 8 280;
|
||||
opacity: .14;
|
||||
transform-origin: 50% 50%;
|
||||
animation: batt-spin 2.2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes batt-spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.modern-dash .batt-center {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.modern-dash .bjorn-portrait {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
position: relative;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
@media(min-width: 400px) {
|
||||
.modern-dash .bjorn-portrait {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.modern-dash .bjorn-portrait img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.5));
|
||||
}
|
||||
|
||||
.modern-dash .bjorn-lvl {
|
||||
position: absolute;
|
||||
right: -8px;
|
||||
bottom: -4px;
|
||||
font-size: 8px;
|
||||
font-weight: 800;
|
||||
padding: 1px 4px;
|
||||
border-radius: 6px;
|
||||
background: var(--_panel);
|
||||
color: var(--accent);
|
||||
border: 1px solid var(--card-border);
|
||||
}
|
||||
|
||||
.modern-dash .batt-val {
|
||||
font-size: 18px;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
text-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.modern-dash .batt-state {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 9px;
|
||||
margin-top: 2px;
|
||||
color: var(--_muted);
|
||||
}
|
||||
|
||||
.modern-dash .hide-mobile {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media(min-width: 1200px) {
|
||||
.modern-dash .hide-mobile {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
.modern-dash .batt-indicator svg {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
stroke: currentColor;
|
||||
fill: none;
|
||||
stroke-width: 2;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/* System Bars Widget */
|
||||
.modern-dash .sys-bars {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.modern-dash .sys-row .sys-lbl {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
color: var(--_muted);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.modern-dash .sys-vals {
|
||||
color: var(--_ink);
|
||||
font-weight: 600;
|
||||
font-family: ui-monospace, monospace;
|
||||
}
|
||||
|
||||
.modern-dash .bar {
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
border-radius: 4px;
|
||||
background: color-mix(in oklab, var(--_ink) 10%, transparent);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.modern-dash .bar i {
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 0%;
|
||||
border-radius: 4px;
|
||||
background: linear-gradient(90deg, var(--accent), var(--_acid2));
|
||||
transition: width 0.5s ease;
|
||||
}
|
||||
|
||||
.modern-dash .bar i.warm {
|
||||
background: linear-gradient(90deg, #ffd166, #ffbe55);
|
||||
}
|
||||
|
||||
.modern-dash .bar i.hot {
|
||||
background: linear-gradient(90deg, #ff4d6d, #ff6b6b);
|
||||
}
|
||||
|
||||
/* Connectivity Card */
|
||||
.modern-dash .net-card {
|
||||
padding: var(--pad);
|
||||
}
|
||||
|
||||
.modern-dash .net-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.modern-dash .net-title {
|
||||
font-size: 14px;
|
||||
font-weight: 800;
|
||||
color: var(--_ink);
|
||||
}
|
||||
|
||||
.modern-dash .net-badge-wrap {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: var(--_muted);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.modern-dash .net-badge {
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
font-size: 10px;
|
||||
font-weight: 800;
|
||||
background: color-mix(in oklab, var(--danger, #ff4d6d) 20%, transparent);
|
||||
color: var(--danger, #ff4d6d);
|
||||
border: 1px solid color-mix(in oklab, var(--danger, #ff4d6d) 40%, transparent);
|
||||
}
|
||||
|
||||
.modern-dash .net-badge.net-on {
|
||||
background: color-mix(in oklab, var(--ok) 20%, transparent);
|
||||
color: var(--ok);
|
||||
border-color: color-mix(in oklab, var(--ok) 40%, transparent);
|
||||
}
|
||||
|
||||
.modern-dash .conn-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.modern-dash .conn-box {
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--card-border);
|
||||
border-radius: 12px;
|
||||
padding: 10px 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
position: relative;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.modern-dash .conn-box:hover {
|
||||
background: color-mix(in oklab, var(--_panel) 80%, transparent);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.modern-dash .conn-icon svg {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
stroke: var(--_muted);
|
||||
fill: none;
|
||||
stroke-width: 1.5;
|
||||
}
|
||||
|
||||
.modern-dash .conn-box.on .conn-icon svg {
|
||||
stroke: var(--accent);
|
||||
filter: drop-shadow(0 0 6px rgba(0, 255, 154, 0.4));
|
||||
}
|
||||
|
||||
.modern-dash .conn-lbl {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: var(--_ink);
|
||||
}
|
||||
|
||||
.modern-dash .state-pill {
|
||||
font-size: 9px;
|
||||
font-weight: 800;
|
||||
padding: 2px 6px;
|
||||
border-radius: 6px;
|
||||
background: color-mix(in oklab, var(--_ink) 10%, transparent);
|
||||
color: var(--_muted);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.modern-dash .conn-box.on .state-pill {
|
||||
background: color-mix(in oklab, var(--ok) 20%, transparent);
|
||||
color: var(--ok);
|
||||
}
|
||||
|
||||
.modern-dash .conn-det-wrap {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* KPI Grid */
|
||||
.modern-dash .kpi-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--gap);
|
||||
}
|
||||
|
||||
@media(min-width: 480px) {
|
||||
.modern-dash .kpi-grid {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width: 1024px) {
|
||||
.modern-dash .kpi-grid {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
.modern-dash .kpi-box {
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--card-border);
|
||||
border-radius: var(--card-radius);
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
backdrop-filter: var(--glass);
|
||||
-webkit-backdrop-filter: var(--glass);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
|
||||
transition: transform 0.2s, background 0.2s;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.modern-dash .kpi-box:hover {
|
||||
transform: translateY(-2px);
|
||||
background: color-mix(in oklab, var(--_panel) 60%, transparent);
|
||||
border-color: color-mix(in oklab, var(--_border) 100%, transparent);
|
||||
}
|
||||
|
||||
.modern-dash .kpi-ico {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.modern-dash .kpi-ico svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
stroke: var(--_muted);
|
||||
fill: none;
|
||||
stroke-width: 1.5;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.modern-dash .kpi-val {
|
||||
font-size: 20px;
|
||||
font-weight: 800;
|
||||
color: var(--_ink);
|
||||
line-height: 1;
|
||||
margin-bottom: 4px;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.modern-dash .kpi-val.multi-val {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.modern-dash .kpi-val .dim {
|
||||
opacity: 0.6;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
.modern-dash .kpi-lbl {
|
||||
font-size: 10px;
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
color: var(--_muted);
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.modern-dash .kpi-extra {
|
||||
margin-top: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.modern-dash .delta {
|
||||
font-size: 9px;
|
||||
font-weight: 700;
|
||||
padding: 2px 6px;
|
||||
border-radius: 6px;
|
||||
background: color-mix(in oklab, var(--_ink) 10%, transparent);
|
||||
color: var(--_muted);
|
||||
}
|
||||
|
||||
.modern-dash .delta.good {
|
||||
background: color-mix(in oklab, var(--ok) 20%, transparent);
|
||||
color: var(--ok);
|
||||
border: 1px solid color-mix(in oklab, var(--ok) 40%, transparent);
|
||||
}
|
||||
|
||||
.modern-dash .delta.bad {
|
||||
background: color-mix(in oklab, var(--danger, #ff4d6d) 20%, transparent);
|
||||
color: var(--danger, #ff4d6d);
|
||||
border: 1px solid color-mix(in oklab, var(--danger, #ff4d6d) 40%, transparent);
|
||||
}
|
||||
|
||||
/* Footer info */
|
||||
.modern-dash .footer-card {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.modern-dash .footer-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.modern-dash .f-title {
|
||||
font-size: 11px;
|
||||
font-weight: 800;
|
||||
color: var(--_ink);
|
||||
margin-bottom: 2px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.modern-dash .f-title.mt {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.modern-dash .f-val {
|
||||
font-size: 11px;
|
||||
color: var(--_muted);
|
||||
font-family: ui-monospace, monospace;
|
||||
}
|
||||
|
||||
.modern-dash .f-val.gps-state {
|
||||
font-weight: 800;
|
||||
color: var(--accent);
|
||||
}
|
||||
369
web/css/pages/database.css
Normal file
369
web/css/pages/database.css
Normal file
@@ -0,0 +1,369 @@
|
||||
/* ==========================================================================
|
||||
DATABASE
|
||||
========================================================================== */
|
||||
.db-container {
|
||||
--db-row-hover: rgba(0, 255, 154, .06);
|
||||
--db-row-selected: rgba(0, 255, 154, .12);
|
||||
--db-cell-edited: rgba(24, 240, 255, .18);
|
||||
}
|
||||
|
||||
.db-container.page-with-sidebar {
|
||||
height: calc(100vh - var(--h-topbar, 56px) - var(--h-bottombar, 56px) - 24px);
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.db-container .db-toolbar,
|
||||
.db-container .db-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 12px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.db-container .db-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 20;
|
||||
background: var(--grad-topbar);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 12px;
|
||||
padding: 12px;
|
||||
box-shadow: var(--shadow);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.db-container .sticky-actions {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
z-index: 15;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
justify-content: flex-end;
|
||||
padding: 8px;
|
||||
background: linear-gradient(180deg, rgba(0, 0, 0, 0), rgba(0, 0, 0, .4));
|
||||
border-top: 1px solid var(--c-border);
|
||||
border-radius: 12px;
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
.db-container .db-tree {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.db-container .tree-head {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 3;
|
||||
background: var(--grad-card);
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.db-container .db-sidebar-filter {
|
||||
position: sticky;
|
||||
top: 30px;
|
||||
z-index: 2;
|
||||
background: var(--c-panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 10px;
|
||||
padding: 6px 10px;
|
||||
width: 100%;
|
||||
color: var(--ink);
|
||||
font: inherit;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.db-container .tree-search {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
background: var(--c-panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 10px;
|
||||
padding: 6px 8px;
|
||||
}
|
||||
|
||||
.db-container .tree-search input {
|
||||
all: unset;
|
||||
flex: 1;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.db-container .tree-group {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.db-container .db-tree-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 10px;
|
||||
background: var(--c-panel-2);
|
||||
cursor: pointer;
|
||||
transition: .18s;
|
||||
color: var(--ink);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.db-container .db-tree-item:hover {
|
||||
box-shadow: 0 0 0 1px var(--c-border-hi) inset, 0 8px 22px var(--glow-weak);
|
||||
transform: translateX(2px);
|
||||
}
|
||||
|
||||
.db-container .db-tree-item.active {
|
||||
background: linear-gradient(180deg, #0b151c, #091219);
|
||||
outline: 2px solid color-mix(in oklab, var(--acid) 55%, transparent);
|
||||
}
|
||||
|
||||
.db-container .db-tree-item-name {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.db-container .db-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-weight: 700;
|
||||
color: var(--acid);
|
||||
letter-spacing: .08em;
|
||||
}
|
||||
|
||||
.db-container .db-controls {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.db-container .db-search-input {
|
||||
background: var(--c-panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 10px;
|
||||
padding: 0 12px;
|
||||
min-width: 240px;
|
||||
flex: 1;
|
||||
color: var(--ink);
|
||||
height: 36px;
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.db-container .db-search-input:focus {
|
||||
outline: none;
|
||||
border-color: color-mix(in oklab, var(--acid) 55%, var(--c-border-strong));
|
||||
box-shadow: 0 0 0 3px color-mix(in oklab, var(--acid) 20%, transparent);
|
||||
}
|
||||
|
||||
.db-container .db-opts {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.db-container .hint {
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.db-container .sep {
|
||||
width: 1px;
|
||||
height: 24px;
|
||||
background: var(--c-border);
|
||||
margin: 0 4px;
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
.db-container .db-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
min-height: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.db-container .db-table-wrap {
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 12px;
|
||||
background: var(--grad-card);
|
||||
box-shadow: var(--shadow);
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.db-container table.db {
|
||||
width: max-content;
|
||||
min-width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
.db-container .db-table-wrap table.db thead th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 5;
|
||||
background: var(--c-panel);
|
||||
border-bottom: 1px solid var(--c-border-strong);
|
||||
text-align: left;
|
||||
padding: 10px;
|
||||
font-weight: 700;
|
||||
color: var(--acid);
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.db-container .db tbody td {
|
||||
padding: 8px 10px;
|
||||
border-bottom: 1px dashed var(--c-border-muted);
|
||||
vertical-align: middle;
|
||||
background: var(--grad-card);
|
||||
}
|
||||
|
||||
.db-container .db tbody tr:hover {
|
||||
background: var(--db-row-hover);
|
||||
}
|
||||
|
||||
.db-container .db tbody tr.selected {
|
||||
background: var(--db-row-selected);
|
||||
outline: 1px solid var(--c-border-hi);
|
||||
}
|
||||
|
||||
.db-container .cell {
|
||||
display: block;
|
||||
min-width: 80px;
|
||||
max-width: 520px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.db-container .cell[contenteditable="true"] {
|
||||
outline: 0;
|
||||
border-radius: 6px;
|
||||
transition: .12s;
|
||||
padding: 2px 6px;
|
||||
}
|
||||
|
||||
.db-container .cell[contenteditable="true"]:focus {
|
||||
background: var(--db-cell-focus);
|
||||
box-shadow: 0 0 0 1px var(--c-border-hi) inset;
|
||||
}
|
||||
|
||||
.db-container .cell.edited {
|
||||
background: var(--db-cell-edited);
|
||||
}
|
||||
|
||||
.db-container .pk {
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.db-container .cols-drawer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.db-container .cols-drawer.open {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.db-container .db-page {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.db-container .sticky-col-cell {
|
||||
position: sticky;
|
||||
z-index: 3;
|
||||
background: var(--grad-card);
|
||||
box-shadow: 1px 0 0 0 var(--c-border-strong), -1px 0 0 0 var(--c-border);
|
||||
}
|
||||
|
||||
.db-container .sticky-col-head {
|
||||
position: sticky;
|
||||
z-index: 3;
|
||||
background: var(--grad-card);
|
||||
box-shadow: 1px 0 0 0 var(--c-border-strong), -1px 0 0 0 var(--c-border);
|
||||
}
|
||||
|
||||
.db-container .sticky-check,
|
||||
.db-container .sticky-col-head.sticky-check {
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.db-container th.is-sticky .sticky-dot::after {
|
||||
content: "\25CF";
|
||||
margin-left: 6px;
|
||||
font-size: 10px;
|
||||
color: var(--acid);
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
@keyframes db-blinkChange {
|
||||
from {
|
||||
box-shadow: 0 0 0 0 var(--acid-22);
|
||||
}
|
||||
|
||||
to {
|
||||
box-shadow: 0 0 0 6px transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.db-container .value-changed {
|
||||
animation: db-blinkChange .66s ease;
|
||||
}
|
||||
|
||||
@media (max-width:1100px) {
|
||||
.db-container .db-controls {
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.db-container .db-search-input {
|
||||
min-width: 160px;
|
||||
}
|
||||
|
||||
.db-container .cell {
|
||||
max-width: 60vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width:768px) {
|
||||
.db-container .db-search-input {
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.db-container .db-toolbar,
|
||||
.db-container .db-actions {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.db-container .db-actions .btn {
|
||||
padding: 4px 8px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.db-container .cell {
|
||||
min-width: 60px;
|
||||
max-width: 45vw;
|
||||
}
|
||||
|
||||
.db-container .db-controls {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
3244
web/css/pages/files.css
Normal file
3244
web/css/pages/files.css
Normal file
File diff suppressed because it is too large
Load Diff
403
web/css/pages/loki.css
Normal file
403
web/css/pages/loki.css
Normal file
@@ -0,0 +1,403 @@
|
||||
/* ============================================================
|
||||
Loki (HID Attack Mode) — SPA page styles
|
||||
============================================================ */
|
||||
|
||||
.loki-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
gap: 12px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
/* ── Header bar ─────────────────────────────────────────── */
|
||||
|
||||
.loki-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.loki-title {
|
||||
margin: 0;
|
||||
font-size: 1.3rem;
|
||||
font-weight: 800;
|
||||
color: var(--ink);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.loki-title-icon { font-size: 1.5rem; }
|
||||
|
||||
.loki-controls {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* ── Status bar ─────────────────────────────────────────── */
|
||||
|
||||
.loki-status-bar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
padding: 10px 14px;
|
||||
border-radius: 8px;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--line);
|
||||
font-size: 0.85rem;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.loki-status-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.loki-status-item .label { font-weight: 600; }
|
||||
.loki-status-item .value { color: var(--ink); }
|
||||
|
||||
.loki-status-item .dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
}
|
||||
.loki-status-item .dot.on { background: var(--ok, #10b981); }
|
||||
.loki-status-item .dot.off { background: var(--muted, #888); }
|
||||
|
||||
/* ── Grid: Editor + Library ──────────────────────────────── */
|
||||
|
||||
.loki-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 280px;
|
||||
gap: 12px;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.loki-grid {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: 1fr auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Editor panel ────────────────────────────────────────── */
|
||||
|
||||
.loki-editor-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.loki-editor {
|
||||
flex: 1;
|
||||
min-height: 200px;
|
||||
width: 100%;
|
||||
font-family: 'Courier New', 'Fira Code', monospace;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.5;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: var(--surface);
|
||||
color: var(--ink);
|
||||
resize: vertical;
|
||||
tab-size: 2;
|
||||
white-space: pre;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.loki-editor:focus {
|
||||
outline: 2px solid var(--accent, #3b82f6);
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
.loki-editor-toolbar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.loki-editor-toolbar select {
|
||||
padding: 6px 10px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
background: var(--surface);
|
||||
color: var(--ink);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
/* ── Library panel ───────────────────────────────────────── */
|
||||
|
||||
.loki-library {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
min-height: 0;
|
||||
max-height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.loki-library-section {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: var(--surface);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.loki-library-heading {
|
||||
padding: 8px 12px;
|
||||
font-weight: 700;
|
||||
font-size: 0.8rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--muted);
|
||||
border-bottom: 1px solid var(--line);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.loki-library-heading::after {
|
||||
content: '▾';
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
.loki-library-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.loki-library-item {
|
||||
padding: 6px 12px;
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
color: var(--ink);
|
||||
border-bottom: 1px solid var(--line-faint, var(--line));
|
||||
transition: background 0.15s;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.loki-library-item:last-child { border-bottom: none; }
|
||||
|
||||
.loki-library-item:hover {
|
||||
background: var(--hover, rgba(0,0,0,0.04));
|
||||
}
|
||||
|
||||
.loki-library-item.active {
|
||||
background: var(--accent-bg, rgba(59, 130, 246, 0.1));
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.loki-library-item .name { flex: 1; }
|
||||
.loki-library-item .badge {
|
||||
font-size: 0.65rem;
|
||||
padding: 1px 5px;
|
||||
border-radius: 4px;
|
||||
background: var(--muted);
|
||||
color: var(--surface, #fff);
|
||||
}
|
||||
|
||||
/* ── Jobs panel ──────────────────────────────────────────── */
|
||||
|
||||
.loki-jobs {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.loki-jobs-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.loki-jobs-header h3 {
|
||||
margin: 0;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.loki-jobs-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.loki-jobs-table th,
|
||||
.loki-jobs-table td {
|
||||
padding: 6px 10px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.loki-jobs-table th {
|
||||
font-weight: 700;
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
font-size: 0.7rem;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.loki-jobs-empty {
|
||||
text-align: center;
|
||||
padding: 16px;
|
||||
color: var(--muted);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
/* ── Job status badges ───────────────────────────────────── */
|
||||
|
||||
.loki-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.loki-badge.running { background: #fef3c7; color: #92400e; }
|
||||
.loki-badge.succeeded { background: #d1fae5; color: #065f46; }
|
||||
.loki-badge.failed { background: #fee2e2; color: #991b1b; }
|
||||
.loki-badge.cancelled { background: #e5e7eb; color: #374151; }
|
||||
.loki-badge.pending { background: #e0e7ff; color: #3730a3; }
|
||||
|
||||
/* ── Buttons ─────────────────────────────────────────────── */
|
||||
|
||||
.loki-btn {
|
||||
padding: 6px 14px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
background: var(--surface);
|
||||
color: var(--ink);
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.loki-btn:hover { background: var(--hover, rgba(0,0,0,0.04)); }
|
||||
|
||||
.loki-btn.primary {
|
||||
background: var(--accent, #3b82f6);
|
||||
color: #fff;
|
||||
border-color: var(--accent, #3b82f6);
|
||||
}
|
||||
.loki-btn.primary:hover { filter: brightness(1.1); }
|
||||
|
||||
.loki-btn.danger {
|
||||
background: var(--danger, #ef4444);
|
||||
color: #fff;
|
||||
border-color: var(--danger, #ef4444);
|
||||
}
|
||||
.loki-btn.danger:hover { filter: brightness(1.1); }
|
||||
|
||||
.loki-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* ── Toggle switch ───────────────────────────────────────── */
|
||||
|
||||
.loki-toggle {
|
||||
position: relative;
|
||||
width: 44px;
|
||||
height: 24px;
|
||||
appearance: none;
|
||||
background: var(--muted, #ccc);
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.loki-toggle:checked { background: var(--ok, #10b981); }
|
||||
|
||||
.loki-toggle::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.loki-toggle:checked::after { transform: translateX(20px); }
|
||||
|
||||
/* ── Disabled overlay ────────────────────────────────────── */
|
||||
|
||||
.loki-disabled-overlay {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.loki-disabled-overlay::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: var(--surface, #fff);
|
||||
opacity: 0.6;
|
||||
pointer-events: all;
|
||||
border-radius: 8px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* ── Quick type ──────────────────────────────────────────── */
|
||||
|
||||
.loki-quick-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.loki-quick-input {
|
||||
flex: 1;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
font-size: 0.8rem;
|
||||
background: var(--surface);
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
/* ── Install banner ─────────────────────────────────────── */
|
||||
|
||||
.loki-install-banner {
|
||||
padding: 16px 20px;
|
||||
background: var(--warn-bg, #fff3cd);
|
||||
border: 1px solid var(--warn-border, #ffc107);
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.loki-install-banner p {
|
||||
margin: 0 0 12px;
|
||||
font-size: 0.85rem;
|
||||
color: var(--ink);
|
||||
}
|
||||
633
web/css/pages/loot.css
Normal file
633
web/css/pages/loot.css
Normal file
@@ -0,0 +1,633 @@
|
||||
/* ==========================================================================
|
||||
LOOT
|
||||
========================================================================== */
|
||||
.loot-container {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
padding: 16px;
|
||||
margin-top: 5px;
|
||||
min-height: calc(100vh - var(--h-topbar, 56px) - var(--h-bottombar, 56px) - 24px);
|
||||
max-height: calc(100vh - var(--h-topbar, 56px) - var(--h-bottombar, 56px) - 24px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
animation: loot-fadeInUp .6s ease-out;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@keyframes loot-fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.loot-container .stats-bar {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
padding: 12px;
|
||||
background: color-mix(in oklab, var(--_panel) 88%, transparent);
|
||||
border: 1px solid var(--_border);
|
||||
border-radius: 12px;
|
||||
box-shadow: var(--_shadow);
|
||||
backdrop-filter: blur(16px);
|
||||
}
|
||||
|
||||
.loot-container .stat-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 16px;
|
||||
background: color-mix(in oklab, var(--_panel) 65%, transparent);
|
||||
border: 1px solid var(--_border);
|
||||
border-radius: 10px;
|
||||
transition: .2s;
|
||||
}
|
||||
|
||||
.loot-container .stat-item:hover {
|
||||
background: color-mix(in oklab, var(--_panel) 78%, transparent);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.loot-container .stat-icon {
|
||||
font-size: 1.2rem;
|
||||
opacity: .95;
|
||||
}
|
||||
|
||||
.loot-container .stat-value {
|
||||
font-size: 1.05rem;
|
||||
font-weight: 800;
|
||||
background: linear-gradient(135deg, var(--_acid), var(--_acid2));
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.loot-container .stat-label {
|
||||
color: var(--_muted);
|
||||
font-size: .75rem;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.loot-container .controls-bar {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.loot-container .search-container {
|
||||
min-width: 200px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.loot-container .search-input {
|
||||
width: 100%;
|
||||
padding: 12px 16px 12px 44px;
|
||||
background: color-mix(in oklab, var(--_panel) 90%, transparent);
|
||||
border: 1px solid var(--_border);
|
||||
border-radius: 12px;
|
||||
color: var(--_ink);
|
||||
font-size: .95rem;
|
||||
backdrop-filter: blur(10px);
|
||||
transition: .2s;
|
||||
}
|
||||
|
||||
.loot-container .search-input:focus {
|
||||
outline: none;
|
||||
border-color: color-mix(in oklab, var(--_acid2) 40%, var(--_border));
|
||||
box-shadow: 0 0 0 3px color-mix(in oklab, var(--_acid2) 18%, transparent);
|
||||
background: color-mix(in oklab, var(--_panel) 96%, transparent);
|
||||
}
|
||||
|
||||
.loot-container .search-icon {
|
||||
position: absolute;
|
||||
left: 16px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: var(--_muted);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.loot-container .clear-search {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: var(--_muted);
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.loot-container .search-input:not(:placeholder-shown)~.clear-search {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.loot-container .view-controls {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.loot-container .view-btn,
|
||||
.loot-container .sort-btn {
|
||||
padding: 10px;
|
||||
background: color-mix(in oklab, var(--_panel) 90%, transparent);
|
||||
border: 1px solid var(--_border);
|
||||
border-radius: 10px;
|
||||
color: var(--_muted);
|
||||
cursor: pointer;
|
||||
transition: .2s;
|
||||
backdrop-filter: blur(10px);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.loot-container .view-btn:hover,
|
||||
.loot-container .sort-btn:hover {
|
||||
background: color-mix(in oklab, var(--_panel) 96%, transparent);
|
||||
color: var(--_ink);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.loot-container .view-btn.active {
|
||||
background: linear-gradient(135deg, color-mix(in oklab, var(--_acid) 20%, transparent), color-mix(in oklab, var(--_acid2) 12%, transparent));
|
||||
color: var(--_ink);
|
||||
border-color: color-mix(in oklab, var(--_acid2) 35%, var(--_border));
|
||||
}
|
||||
|
||||
.loot-container .sort-dropdown {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.loot-container .sort-menu {
|
||||
position: absolute;
|
||||
top: calc(100% + 8px);
|
||||
right: 0;
|
||||
background: color-mix(in oklab, var(--_panel) 98%, transparent);
|
||||
border: 1px solid var(--_border);
|
||||
border-radius: 12px;
|
||||
padding: 8px;
|
||||
min-width: 150px;
|
||||
backdrop-filter: blur(20px);
|
||||
box-shadow: var(--_shadow);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transform: translateY(-10px);
|
||||
transition: .2s;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.loot-container .sort-dropdown.active .sort-menu {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.loot-container .sort-option {
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: .2s;
|
||||
font-size: .9rem;
|
||||
color: var(--_ink);
|
||||
}
|
||||
|
||||
.loot-container .sort-option:hover {
|
||||
background: rgba(255, 255, 255, .05);
|
||||
}
|
||||
|
||||
.loot-container .sort-option.active {
|
||||
color: var(--_ink);
|
||||
background: color-mix(in oklab, var(--_acid2) 14%, transparent);
|
||||
}
|
||||
|
||||
.loot-container .tabs-container {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 4px;
|
||||
background: color-mix(in oklab, var(--_panel) 88%, transparent);
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--_border);
|
||||
backdrop-filter: blur(10px);
|
||||
overflow-x: auto;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.loot-container .tabs-container::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.loot-container .tab {
|
||||
padding: 10px 20px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: .2s;
|
||||
white-space: nowrap;
|
||||
font-size: .9rem;
|
||||
font-weight: 700;
|
||||
position: relative;
|
||||
color: var(--_muted);
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.loot-container .tab:hover {
|
||||
background: rgba(255, 255, 255, .05);
|
||||
color: var(--_ink);
|
||||
}
|
||||
|
||||
.loot-container .tab.active {
|
||||
background: linear-gradient(135deg, color-mix(in oklab, var(--_acid) 16%, transparent), color-mix(in oklab, var(--_acid2) 10%, transparent));
|
||||
color: var(--_ink);
|
||||
border-color: color-mix(in oklab, var(--_acid2) 28%, var(--_border));
|
||||
}
|
||||
|
||||
.loot-container .tab.active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 10%;
|
||||
right: 10%;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, var(--_acid), var(--_acid2));
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.loot-container .tab-badge {
|
||||
display: inline-block;
|
||||
padding: 2px 6px;
|
||||
margin-left: 6px;
|
||||
background: rgba(255, 255, 255, .08);
|
||||
border: 1px solid var(--_border);
|
||||
border-radius: 10px;
|
||||
font-size: .75rem;
|
||||
font-weight: 700;
|
||||
color: var(--_ink);
|
||||
}
|
||||
|
||||
.loot-container .explorer {
|
||||
background: color-mix(in oklab, var(--_panel) 88%, transparent);
|
||||
border-radius: 20px;
|
||||
border: 1px solid var(--_border);
|
||||
backdrop-filter: blur(20px);
|
||||
box-shadow: var(--_shadow);
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
animation: loot-slideIn .6s ease-out;
|
||||
}
|
||||
|
||||
@keyframes loot-slideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-16px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
.loot-container .explorer-content {
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.loot-container .tree-view {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.loot-container .tree-view.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.loot-container .list-view {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.loot-container .list-view.active {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.loot-container .loot-tree-node {
|
||||
margin-bottom: 4px;
|
||||
animation: loot-itemSlide .3s ease-out backwards;
|
||||
margin-left: calc(var(--loot-level, 0) * 8px);
|
||||
}
|
||||
|
||||
@keyframes loot-itemSlide {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-10px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
.loot-container .loot-tree-row {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: 18px 30px minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 12px;
|
||||
cursor: pointer;
|
||||
border-radius: 10px;
|
||||
transition: .2s;
|
||||
border: 1px solid transparent;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
color: var(--_ink);
|
||||
background: color-mix(in oklab, var(--_panel) 86%, transparent);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.loot-container .loot-tree-row::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .05), transparent);
|
||||
transform: translateX(-100%);
|
||||
transition: transform .6s;
|
||||
}
|
||||
|
||||
.loot-container .loot-tree-row:hover::before {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.loot-container .loot-tree-row:hover {
|
||||
border-color: color-mix(in oklab, var(--_acid2) 26%, var(--_border));
|
||||
background: color-mix(in oklab, var(--_panel) 94%, transparent);
|
||||
}
|
||||
|
||||
.loot-container .loot-tree-icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 8px;
|
||||
font-size: 1.1rem;
|
||||
flex-shrink: 0;
|
||||
background: color-mix(in oklab, var(--_acid) 12%, transparent);
|
||||
color: var(--_ink);
|
||||
}
|
||||
|
||||
.loot-container .folder-icon {
|
||||
background: color-mix(in oklab, var(--_acid) 10%, transparent);
|
||||
color: var(--_ink);
|
||||
}
|
||||
|
||||
.loot-container .loot-tree-name {
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.loot-container .loot-tree-chevron {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--_muted);
|
||||
transition: transform .3s cubic-bezier(.4, 0, .2, 1);
|
||||
font-size: .75rem;
|
||||
}
|
||||
|
||||
.loot-container .loot-tree-meta {
|
||||
justify-self: end;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--_border);
|
||||
font-size: .72rem;
|
||||
color: var(--_muted);
|
||||
background: color-mix(in oklab, var(--_panel) 76%, transparent);
|
||||
}
|
||||
|
||||
.loot-container .loot-tree-node.expanded .loot-tree-chevron {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.loot-container .loot-tree-children {
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
margin-left: 10px;
|
||||
padding-left: 14px;
|
||||
border-left: 1px dashed color-mix(in oklab, var(--_border) 82%, transparent);
|
||||
}
|
||||
|
||||
.loot-container .loot-tree-node.expanded .loot-tree-children {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.loot-container .file-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 12px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
transition: .2s;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.loot-container .file-item:hover {
|
||||
background: rgba(255, 255, 255, .04);
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
.loot-container .file-item:active {
|
||||
transform: translateX(2px) scale(.98);
|
||||
}
|
||||
|
||||
.loot-container .file-item.is-tree-file {
|
||||
margin-left: calc(var(--loot-level, 0) * 8px);
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid transparent;
|
||||
background: color-mix(in oklab, var(--_panel) 82%, transparent);
|
||||
}
|
||||
|
||||
.loot-container .file-item.is-tree-file:hover {
|
||||
transform: none;
|
||||
border-color: color-mix(in oklab, var(--_acid2) 22%, var(--_border));
|
||||
}
|
||||
|
||||
.loot-container .file-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
margin-right: 12px;
|
||||
font-size: .9rem;
|
||||
flex-shrink: 0;
|
||||
color: var(--_ink);
|
||||
background: color-mix(in oklab, var(--_panel) 75%, transparent);
|
||||
}
|
||||
|
||||
.loot-container .file-icon.ssh {
|
||||
background: color-mix(in oklab, var(--_acid) 12%, transparent);
|
||||
}
|
||||
|
||||
.loot-container .file-icon.sql {
|
||||
background: color-mix(in oklab, var(--_acid2) 12%, transparent);
|
||||
}
|
||||
|
||||
.loot-container .file-icon.smb {
|
||||
background: color-mix(in oklab, var(--_acid2) 16%, transparent);
|
||||
}
|
||||
|
||||
.loot-container .file-icon.other {
|
||||
background: color-mix(in oklab, var(--_panel) 75%, transparent);
|
||||
}
|
||||
|
||||
.loot-container .file-name {
|
||||
flex: 1;
|
||||
font-size: .9rem;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--_ink);
|
||||
}
|
||||
|
||||
.loot-container .file-type {
|
||||
padding: 3px 8px;
|
||||
border-radius: 6px;
|
||||
font-size: .7rem;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .05em;
|
||||
margin-left: 8px;
|
||||
border: 1px solid var(--_border);
|
||||
color: var(--_ink);
|
||||
background: color-mix(in oklab, var(--_panel) 80%, transparent);
|
||||
}
|
||||
|
||||
.loot-container .file-type.ssh {
|
||||
background: color-mix(in oklab, var(--_acid) 12%, transparent);
|
||||
}
|
||||
|
||||
.loot-container .file-type.sql {
|
||||
background: color-mix(in oklab, var(--_acid2) 12%, transparent);
|
||||
}
|
||||
|
||||
.loot-container .file-type.smb {
|
||||
background: color-mix(in oklab, var(--_acid2) 16%, transparent);
|
||||
}
|
||||
|
||||
.loot-container .no-results {
|
||||
text-align: center;
|
||||
color: var(--_muted);
|
||||
padding: 40px;
|
||||
font-size: .95rem;
|
||||
}
|
||||
|
||||
.loot-container .no-results-icon {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 16px;
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.loot-container .loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.loot-container .loading-spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 3px solid var(--_border);
|
||||
border-top-color: var(--_acid2);
|
||||
border-radius: 50%;
|
||||
animation: loot-spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes loot-spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width:768px) {
|
||||
.loot-container {
|
||||
padding: 12px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.loot-container .controls-bar {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.loot-container .search-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.loot-container .view-controls {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.loot-container .tabs-container {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.loot-container .tab {
|
||||
padding: 8px 14px;
|
||||
font-size: .85rem;
|
||||
}
|
||||
|
||||
.loot-container .explorer-content {
|
||||
padding: 12px;
|
||||
max-height: calc(100vh - 320px);
|
||||
}
|
||||
|
||||
.loot-container .loot-tree-row {
|
||||
grid-template-columns: 16px 26px minmax(0, 1fr);
|
||||
gap: 8px;
|
||||
padding: 9px 10px;
|
||||
}
|
||||
|
||||
.loot-container .loot-tree-meta {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.loot-container .loot-tree-children {
|
||||
margin-left: 8px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.loot-container .stat-item {
|
||||
padding: 6px 10px;
|
||||
}
|
||||
|
||||
.loot-container .stat-value {
|
||||
font-size: .95rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (hover:none) {
|
||||
.loot-container .loot-tree-row:active {
|
||||
background: rgba(255, 255, 255, .06);
|
||||
}
|
||||
}
|
||||
|
||||
538
web/css/pages/netkb.css
Normal file
538
web/css/pages/netkb.css
Normal file
@@ -0,0 +1,538 @@
|
||||
/* ===== NETKB ===== */
|
||||
.netkb-container {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.netkb-container .hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.netkb-container .netkb-toolbar-wrap {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 500;
|
||||
backdrop-filter: saturate(1.1) blur(6px);
|
||||
}
|
||||
|
||||
.netkb-container .netkb-toolbar {
|
||||
position: relative;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 12px;
|
||||
border: 1px solid var(--c-border-strong);
|
||||
padding: 8px 10px;
|
||||
box-shadow: var(--shadow);
|
||||
background: var(--panel);
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
/* .segmented styles now inherited from global.css */
|
||||
|
||||
.netkb-container .kb-switch {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-weight: 700;
|
||||
color: var(--muted);
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 999px;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
|
||||
.netkb-container .kb-switch input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.netkb-container .kb-switch .track {
|
||||
width: 44px;
|
||||
height: 24px;
|
||||
border-radius: 999px;
|
||||
background: var(--c-panel-2);
|
||||
position: relative;
|
||||
border: 1px solid var(--c-border);
|
||||
}
|
||||
|
||||
.netkb-container .kb-switch .thumb {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background: var(--ink);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, .4);
|
||||
transition: left .18s ease, background .18s ease;
|
||||
}
|
||||
|
||||
.netkb-container .kb-switch input:checked~.track .thumb {
|
||||
left: 22px;
|
||||
background: var(--acid);
|
||||
}
|
||||
|
||||
.netkb-container .kb-switch[data-on="true"] {
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.netkb-container .icon-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 12px;
|
||||
background: var(--c-panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
box-shadow: var(--shadow);
|
||||
cursor: pointer;
|
||||
transition: transform .12s ease, box-shadow .12s ease;
|
||||
}
|
||||
|
||||
.netkb-container .icon-btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--shadow-hover);
|
||||
}
|
||||
|
||||
.netkb-container .icon-btn svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: var(--ink);
|
||||
}
|
||||
|
||||
.netkb-container .search-pop {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 54px;
|
||||
display: none;
|
||||
min-width: 260px;
|
||||
background: var(--c-panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 12px;
|
||||
padding: 10px;
|
||||
box-shadow: var(--shadow-hover);
|
||||
}
|
||||
|
||||
.netkb-container .search-pop.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.netkb-container .search-input-wrap {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.netkb-container .search-pop input {
|
||||
width: 100%;
|
||||
padding: 10px 32px 10px 12px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid var(--c-border);
|
||||
background: var(--c-panel-2);
|
||||
color: var(--ink);
|
||||
font-weight: 700;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.netkb-container .search-clear {
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
transition: background .15s;
|
||||
}
|
||||
|
||||
.netkb-container .search-clear:hover {
|
||||
background: var(--c-border-strong);
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.netkb-container .search-hint {
|
||||
margin-top: 6px;
|
||||
font-size: .85rem;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.netkb-container .card-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.netkb-container .card {
|
||||
background: var(--grad-card);
|
||||
color: var(--ink);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 18px;
|
||||
box-shadow: var(--shadow);
|
||||
width: min(380px, 100%);
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
overflow: hidden;
|
||||
min-width: 0;
|
||||
transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease, background .15s ease;
|
||||
}
|
||||
|
||||
.netkb-container .card:hover {
|
||||
box-shadow: var(--shadow-hover);
|
||||
border-color: var(--c-border-hi);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.netkb-container .card.alive .card-title {
|
||||
color: var(--ok);
|
||||
}
|
||||
|
||||
.netkb-container .card.not-alive {
|
||||
background: var(--kb-offline-bg);
|
||||
border-color: var(--kb-offline-brd);
|
||||
color: color-mix(in oklab, var(--muted) 90%, var(--ink) 10%);
|
||||
box-shadow: 0 0 0 1px var(--kb-offline-brd), 0 0 0 2px color-mix(in oklab, var(--kb-offline-ring) 26%, transparent), var(--shadow);
|
||||
}
|
||||
|
||||
.netkb-container .card.not-alive .card-title {
|
||||
color: color-mix(in oklab, var(--muted) 85%, var(--ink) 15%);
|
||||
}
|
||||
|
||||
.netkb-container .card-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.netkb-container .card-title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 800;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.netkb-container .card-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.netkb-container .card.list {
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.netkb-container .card.list .card-title {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.netkb-container .chip {
|
||||
display: inline-block;
|
||||
padding: .32rem .7rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--c-border-strong);
|
||||
background: var(--kb-chip);
|
||||
color: var(--ink);
|
||||
font-weight: 700;
|
||||
font-size: .92rem;
|
||||
}
|
||||
|
||||
.netkb-container .chip.host {
|
||||
background: var(--kb-hostname-bg);
|
||||
}
|
||||
|
||||
.netkb-container .chip.ip {
|
||||
background: var(--kb-ip-bg);
|
||||
}
|
||||
|
||||
.netkb-container .chip.mac {
|
||||
background: var(--kb-mac-bg);
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.netkb-container .chip.vendor {
|
||||
background: var(--kb-vendor-bg);
|
||||
}
|
||||
|
||||
.netkb-container .chip.essid {
|
||||
background: var(--kb-essid-bg);
|
||||
}
|
||||
|
||||
.netkb-container .chip.port {
|
||||
background: var(--kb-ports-bg);
|
||||
border-color: var(--c-border-hi);
|
||||
}
|
||||
|
||||
.netkb-container .port-bubbles {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.netkb-container .status-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.netkb-container .badge {
|
||||
background: var(--c-panel-2);
|
||||
color: var(--ink);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 14px;
|
||||
padding: 8px 10px;
|
||||
min-width: 0;
|
||||
flex: 1 1 120px;
|
||||
max-width: 100%;
|
||||
text-align: center;
|
||||
box-shadow: var(--shadow);
|
||||
transition: transform .12s ease, box-shadow .12s ease, opacity .12s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.netkb-container .badge .badge-header {
|
||||
font-weight: 800;
|
||||
opacity: .95;
|
||||
}
|
||||
|
||||
.netkb-container .badge .badge-status {
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.netkb-container .badge .badge-timestamp {
|
||||
font-size: .85em;
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
.netkb-container .badge.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.netkb-container .badge:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--shadow-hover);
|
||||
}
|
||||
|
||||
.netkb-container .badge.success {
|
||||
background: linear-gradient(180deg, color-mix(in oklab, var(--ok) 12%, transparent), transparent);
|
||||
}
|
||||
|
||||
.netkb-container .badge.failed {
|
||||
background: linear-gradient(180deg, color-mix(in oklab, var(--danger) 18%, transparent), transparent);
|
||||
}
|
||||
|
||||
.netkb-container .badge.pending {
|
||||
background: linear-gradient(180deg, color-mix(in oklab, var(--muted) 12%, transparent), transparent);
|
||||
}
|
||||
|
||||
.netkb-container .badge.expired {
|
||||
background: linear-gradient(180deg, color-mix(in oklab, var(--warning) 18%, transparent), transparent);
|
||||
}
|
||||
|
||||
.netkb-container .badge.cancelled {
|
||||
background: linear-gradient(180deg, color-mix(in oklab, var(--c-panel) 18%, transparent), transparent);
|
||||
}
|
||||
|
||||
.netkb-container .badge.running {
|
||||
background: linear-gradient(180deg, color-mix(in oklab, #18f0ff 14%, transparent), transparent);
|
||||
overflow: hidden;
|
||||
animation: kb-badgePulse 1.6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.netkb-container .badge.running::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: var(--kb-badge-shimmer);
|
||||
animation: kb-shimmer 1.8s linear infinite;
|
||||
}
|
||||
|
||||
.netkb-container .badge.running::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: -20%;
|
||||
background: linear-gradient(130deg, transparent 40%, rgba(255, 255, 255, .06) 50%, transparent 60%);
|
||||
animation: kb-sheen 2.2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes kb-shimmer {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes kb-sheen {
|
||||
0% {
|
||||
transform: translateX(-30%);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(30%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes kb-badgePulse {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 rgba(24, 240, 255, .12);
|
||||
}
|
||||
|
||||
50% {
|
||||
box-shadow: 0 0 0 8px rgba(24, 240, 255, .04);
|
||||
}
|
||||
}
|
||||
|
||||
.netkb-container .table-wrap {
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 14px;
|
||||
overflow: auto;
|
||||
background: var(--panel);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.netkb-container .table-inner {
|
||||
min-width: max-content;
|
||||
}
|
||||
|
||||
.netkb-container table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
.netkb-container thead th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
background: var(--c-panel);
|
||||
color: var(--ink);
|
||||
border-bottom: 1px solid var(--c-border-strong);
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.netkb-container tbody td {
|
||||
border-bottom: 1px solid var(--c-border);
|
||||
padding: 10px;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.netkb-container th:first-child,
|
||||
.netkb-container td:first-child {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
background: var(--panel);
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.netkb-container .filter-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-left: 6px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.netkb-container mark.hl {
|
||||
background: color-mix(in oklab, var(--acid) 25%, transparent);
|
||||
color: var(--ink);
|
||||
padding: 0 .15em;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.netkb-container .segmented button:focus-visible,
|
||||
.netkb-container .icon-btn:focus-visible,
|
||||
.netkb-container .kb-switch:has(input:focus-visible) {
|
||||
outline: 2px solid var(--acid);
|
||||
outline-offset: 2px;
|
||||
box-shadow: 0 0 0 3px color-mix(in oklab, var(--acid) 25%, transparent);
|
||||
}
|
||||
|
||||
@media (max-width:720px) {
|
||||
.netkb-container {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.netkb-container .card {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.netkb-container .segmented button[data-view="grid"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.netkb-container .netkb-toolbar-wrap {
|
||||
position: relative;
|
||||
top: auto;
|
||||
}
|
||||
|
||||
.netkb-container .netkb-toolbar {
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.netkb-container .table-wrap {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.netkb-container .table-inner>table {
|
||||
min-width: 760px;
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
.netkb-container thead th,
|
||||
.netkb-container tbody td {
|
||||
min-width: 80px;
|
||||
font-size: .85rem;
|
||||
padding: 8px 6px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.netkb-container .chip {
|
||||
font-size: .8rem;
|
||||
padding: .25rem .5rem;
|
||||
}
|
||||
|
||||
.netkb-container .badge {
|
||||
min-width: 120px;
|
||||
padding: 6px 8px;
|
||||
}
|
||||
}
|
||||
|
||||
605
web/css/pages/network.css
Normal file
605
web/css/pages/network.css
Normal file
@@ -0,0 +1,605 @@
|
||||
/* ===== NETWORK ===== */
|
||||
.network-container {
|
||||
padding: 12px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: calc(100vh - var(--h-topbar, 56px) - var(--h-bottombar, 56px) - 16px);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.network-container.is-table-view .ocean-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.network-container .nv-toolbar-wrap {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
margin: 0 0 10px 0;
|
||||
z-index: 500;
|
||||
backdrop-filter: saturate(1.1) blur(6px);
|
||||
}
|
||||
|
||||
.network-container .nv-toolbar {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 16px;
|
||||
padding: 8px 10px;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.network-container .nv-search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
background: var(--c-panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 12px;
|
||||
padding: 6px 10px;
|
||||
min-width: 240px;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.network-container .nv-search-icon {
|
||||
font-size: 16px;
|
||||
flex-shrink: 0;
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
.network-container .nv-search input {
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
color: var(--ink);
|
||||
font-weight: 700;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.network-container .nv-search-clear {
|
||||
flex-shrink: 0;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
transition: background .15s;
|
||||
}
|
||||
|
||||
.network-container .nv-search-clear:hover {
|
||||
background: var(--c-border-strong);
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.network-container .segmented {
|
||||
display: inline-flex;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 999px;
|
||||
padding: 4px;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.network-container .segmented button {
|
||||
appearance: none;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
font-weight: 700;
|
||||
padding: 8px 14px;
|
||||
border-radius: 999px;
|
||||
cursor: pointer;
|
||||
transition: background .15s ease, color .15s ease, transform .1s ease;
|
||||
}
|
||||
|
||||
.network-container .segmented button[aria-pressed="true"] {
|
||||
background: var(--grad-card);
|
||||
color: var(--ink);
|
||||
box-shadow: inset 0 0 0 1px var(--c-border-hi), 0 6px 24px var(--glow-weak);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.network-container .nv-switch {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-weight: 700;
|
||||
color: var(--muted);
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 999px;
|
||||
padding: 6px 10px;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.network-container .nv-switch input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.network-container .nv-switch .track {
|
||||
width: 44px;
|
||||
height: 24px;
|
||||
border-radius: 999px;
|
||||
background: var(--c-panel-2);
|
||||
position: relative;
|
||||
border: 1px solid var(--c-border);
|
||||
}
|
||||
|
||||
.network-container .nv-switch .thumb {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background: var(--ink);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, .4);
|
||||
transition: left .18s ease, background .18s ease;
|
||||
}
|
||||
|
||||
.network-container .nv-switch input:checked~.track .thumb {
|
||||
left: 22px;
|
||||
background: var(--acid);
|
||||
}
|
||||
|
||||
.network-container .nv-switch[data-on="true"] {
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.network-container .table-wrap {
|
||||
position: relative;
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 14px;
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
background: var(--c-panel, #0b1218);
|
||||
box-shadow: var(--shadow);
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.network-container table.network-table {
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
table-layout: auto;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
.network-container thead th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 3;
|
||||
background: var(--c-panel, #0b1218);
|
||||
color: var(--ink);
|
||||
border-bottom: 1px solid var(--c-border-strong);
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
box-shadow: inset 0 -1px 0 var(--c-border);
|
||||
}
|
||||
|
||||
.network-container tbody tr {
|
||||
background: color-mix(in oklab, var(--c-panel, #0b1218) 94%, var(--acid) 6%);
|
||||
transition: .25s ease;
|
||||
}
|
||||
|
||||
.network-container tbody tr:hover {
|
||||
background: color-mix(in oklab, var(--c-panel, #0b1218) 84%, var(--acid) 16%);
|
||||
}
|
||||
|
||||
.network-container td {
|
||||
padding: 10px;
|
||||
color: var(--ink, #fff);
|
||||
background: color-mix(in oklab, var(--c-panel, #0b1218) 97%, var(--acid) 3%);
|
||||
vertical-align: top;
|
||||
white-space: normal;
|
||||
border-bottom: 1px solid color-mix(in oklab, var(--c-border) 65%, transparent);
|
||||
}
|
||||
|
||||
.network-container th.hosts-header {
|
||||
left: 0;
|
||||
position: sticky;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.network-container td.hosts-cell {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
background: color-mix(in oklab, var(--c-panel, #0b1218) 91%, var(--acid) 9%);
|
||||
}
|
||||
|
||||
.network-container thead th.sort-asc::after {
|
||||
content: '\2191';
|
||||
margin-left: 8px;
|
||||
color: #00b894;
|
||||
}
|
||||
|
||||
.network-container thead th.sort-desc::after {
|
||||
content: '\2193';
|
||||
margin-left: 8px;
|
||||
color: #00b894;
|
||||
}
|
||||
|
||||
.network-container .hosts-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: .55rem;
|
||||
flex-wrap: wrap;
|
||||
min-width: 320px;
|
||||
}
|
||||
|
||||
.network-container .bubble {
|
||||
padding: .5rem 1rem;
|
||||
border-radius: 6px;
|
||||
font-size: .9rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: .5rem;
|
||||
transition: .2s;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
.network-container .bubble.bubble-empty {
|
||||
background: color-mix(in oklab, var(--muted) 18%, transparent);
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.network-container .bubble.essid {
|
||||
background: linear-gradient(135deg, #272727, #2560a1);
|
||||
color: #fff;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
font-size: .9em;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.network-container .bubble.ip-address {
|
||||
background: linear-gradient(135deg, #272727, #00cec9);
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.network-container .bubble.hostname {
|
||||
background: linear-gradient(135deg, #5b5c5a, #e7951a);
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.network-container .bubble.mac-address {
|
||||
background: linear-gradient(135deg, #404041, #636e72);
|
||||
color: #b2bec3;
|
||||
font-family: monospace;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.network-container .bubble.vendor {
|
||||
background: linear-gradient(135deg, #5b5c5a, #0a4952);
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.network-container .ports-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .45rem;
|
||||
align-items: center;
|
||||
min-width: 220px;
|
||||
}
|
||||
|
||||
.network-container .port-bubble {
|
||||
background: linear-gradient(135deg, #1f2c33, #00b894);
|
||||
color: #eafff8;
|
||||
padding: .4rem .8rem;
|
||||
border-radius: 20px;
|
||||
font-size: .85rem;
|
||||
border: 1px solid color-mix(in oklab, #00b894 40%, transparent);
|
||||
max-width: fit-content;
|
||||
transition: .2s;
|
||||
}
|
||||
|
||||
.network-container .port-bubble.is-empty {
|
||||
background: color-mix(in oklab, var(--panel) 90%, transparent);
|
||||
color: var(--muted);
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
.network-container .port-bubble:hover {
|
||||
transform: scale(1.08);
|
||||
box-shadow: 0 2px 8px rgba(9, 132, 227, .3);
|
||||
}
|
||||
|
||||
/* Ports cell — match hosts-cell vertical alignment */
|
||||
.network-container td.ports-cell {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* Sticky pin button */
|
||||
.network-container .nv-pin-btn {
|
||||
display: none; /* shown on mobile only */
|
||||
appearance: none;
|
||||
border: 1px solid var(--c-border);
|
||||
background: var(--c-panel, #0b1218);
|
||||
color: var(--ink);
|
||||
border-radius: 6px;
|
||||
width: 28px;
|
||||
height: 24px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
line-height: 1;
|
||||
transition: .15s;
|
||||
}
|
||||
|
||||
.network-container .nv-pin-btn.active {
|
||||
background: color-mix(in oklab, var(--acid) 20%, var(--c-panel));
|
||||
border-color: var(--acid);
|
||||
box-shadow: 0 0 6px color-mix(in oklab, var(--acid) 30%, transparent);
|
||||
}
|
||||
|
||||
/* Dynamic sticky columns */
|
||||
.network-container .nv-sticky-col {
|
||||
position: sticky !important;
|
||||
z-index: 2;
|
||||
background: color-mix(in oklab, var(--c-panel, #0b1218) 97%, var(--acid) 3%);
|
||||
box-shadow: 2px 0 4px rgba(0, 0, 0, .15);
|
||||
}
|
||||
|
||||
.network-container thead .nv-sticky-col {
|
||||
z-index: 5;
|
||||
background: var(--c-panel, #0b1218);
|
||||
}
|
||||
|
||||
.network-container .segmented button:focus-visible,
|
||||
.network-container .nv-search input:focus-visible,
|
||||
.network-container .nv-switch:has(input:focus-visible) {
|
||||
outline: 2px solid var(--acid);
|
||||
outline-offset: 2px;
|
||||
box-shadow: 0 0 0 3px color-mix(in oklab, var(--acid) 25%, transparent);
|
||||
}
|
||||
|
||||
/* Ocean / Map */
|
||||
.network-container .ocean-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
background: radial-gradient(ellipse at center, #0a4b7a 0%, #01162e 60%, #00050a 100%);
|
||||
}
|
||||
|
||||
.network-container .ocean-surface {
|
||||
position: absolute;
|
||||
top: -50%;
|
||||
left: -50%;
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
opacity: 0.3;
|
||||
background-image: repeating-radial-gradient(circle at 50% 50%, transparent 0, transparent 20px, rgba(255, 255, 255, 0.02) 25px, transparent 40px);
|
||||
animation: nv-oceanDrift 60s linear infinite alternate;
|
||||
}
|
||||
|
||||
.network-container .ocean-caustics {
|
||||
position: absolute;
|
||||
top: -100%;
|
||||
left: -100%;
|
||||
width: 300%;
|
||||
height: 300%;
|
||||
opacity: 0.3;
|
||||
mix-blend-mode: overlay;
|
||||
animation: nv-causticFlow 30s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes nv-oceanDrift {
|
||||
0% {
|
||||
transform: translate(0, 0) rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translate(-40px, 20px) rotate(1deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes nv-causticFlow {
|
||||
0% {
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translate(-100px, -50px);
|
||||
}
|
||||
}
|
||||
|
||||
.network-container #visualization-container {
|
||||
display: none;
|
||||
position: relative;
|
||||
min-height: calc(100vh - var(--h-topbar, 56px) - var(--h-bottombar, 56px) - 100px);
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
border-radius: 14px;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--c-border-strong);
|
||||
box-shadow: var(--shadow);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.network-container .link {
|
||||
stroke: rgba(255, 255, 255, 0.15);
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.network-container .node {
|
||||
cursor: pointer;
|
||||
transition: opacity 0.5s;
|
||||
}
|
||||
|
||||
.network-container .foam-ring {
|
||||
fill: rgba(240, 248, 255, 0.3);
|
||||
mix-blend-mode: screen;
|
||||
animation: nv-foamPulse 4s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
.network-container .foam-ring:nth-child(2) {
|
||||
animation-delay: -1s;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
@keyframes nv-foamPulse {
|
||||
0% {
|
||||
transform: scale(0.9) rotate(0deg);
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1.1) rotate(10deg);
|
||||
opacity: 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
.network-container .sonar-wave {
|
||||
fill: none;
|
||||
stroke: #ffb703;
|
||||
stroke-width: 2px;
|
||||
animation: nv-sonar 4s infinite ease-out;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes nv-sonar {
|
||||
0% {
|
||||
r: 40px;
|
||||
opacity: 0.6;
|
||||
stroke-width: 3px;
|
||||
}
|
||||
|
||||
100% {
|
||||
r: 300px;
|
||||
opacity: 0;
|
||||
stroke-width: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.network-container .label-group {
|
||||
transition: transform 0.1s;
|
||||
}
|
||||
|
||||
.network-container .label-bg {
|
||||
fill: rgba(0, 20, 40, 0.8);
|
||||
rx: 4;
|
||||
stroke: rgba(255, 255, 255, 0.1);
|
||||
stroke-width: 0.5px;
|
||||
}
|
||||
|
||||
.network-container .label-text {
|
||||
font-size: 10px;
|
||||
fill: #fff;
|
||||
font-family: monospace;
|
||||
text-shadow: 0 1px 2px #000;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.network-container .d3-tooltip {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
background: rgba(2, 16, 31, 0.95);
|
||||
border: 1px solid #219ebc;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
font-size: 0.85rem;
|
||||
color: #fff;
|
||||
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.5);
|
||||
transform: translate(-50%, -110%);
|
||||
transition: opacity 0.2s;
|
||||
white-space: nowrap;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.network-container .nv-toolbar {
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.network-container .nv-search {
|
||||
min-width: 0;
|
||||
flex: 1 1 220px;
|
||||
}
|
||||
|
||||
.network-container .segmented {
|
||||
order: 3;
|
||||
}
|
||||
|
||||
.network-container table.network-table {
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.network-container .hosts-content {
|
||||
min-width: unset;
|
||||
}
|
||||
|
||||
.network-container th.hosts-header,
|
||||
.network-container td.hosts-cell {
|
||||
position: static;
|
||||
}
|
||||
|
||||
.network-container .nv-pin-btn {
|
||||
display: inline-flex;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.network-container {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.network-container .nv-toolbar {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.network-container table.network-table {
|
||||
min-width: 100%;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.network-container td,
|
||||
.network-container th {
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.network-container .bubble {
|
||||
font-size: .82rem;
|
||||
padding: .35rem .65rem;
|
||||
}
|
||||
|
||||
.network-container .port-bubble {
|
||||
font-size: .8rem;
|
||||
padding: .34rem .62rem;
|
||||
}
|
||||
}
|
||||
794
web/css/pages/scheduler.css
Normal file
794
web/css/pages/scheduler.css
Normal file
@@ -0,0 +1,794 @@
|
||||
/* ==========================================================================
|
||||
SCHEDULER
|
||||
========================================================================== */
|
||||
.scheduler-container .toolbar-top {
|
||||
position: sticky;
|
||||
top: calc(var(--h-topbar, 0px) + 5px);
|
||||
z-index: 60;
|
||||
}
|
||||
|
||||
.scheduler-container .controls {
|
||||
position: sticky;
|
||||
top: 1px;
|
||||
z-index: 50;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: .5rem;
|
||||
padding: .6rem .8rem;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 14px;
|
||||
margin: .6rem .6rem 0 .6rem;
|
||||
box-shadow: var(--shadow);
|
||||
backdrop-filter: saturate(1.05) blur(6px);
|
||||
}
|
||||
|
||||
.scheduler-container .pill {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
color: var(--ink);
|
||||
border-radius: 999px;
|
||||
padding: .45rem .8rem;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
font-weight: 700;
|
||||
transition: transform .15s ease, box-shadow .2s ease, background .2s ease, color .2s ease;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.scheduler-container .pill:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 26px rgba(0, 0, 0, .35);
|
||||
}
|
||||
|
||||
.scheduler-container .pill.active {
|
||||
background: var(--grad-card, linear-gradient(135deg, color-mix(in oklab, var(--panel) 92%, transparent), color-mix(in oklab, var(--c-panel) 88%, transparent)));
|
||||
box-shadow: inset 0 0 0 1px var(--c-border-strong), 0 6px 24px var(--glow-weak);
|
||||
}
|
||||
|
||||
.scheduler-container .controls input[type="text"] {
|
||||
flex: 1 1 260px;
|
||||
min-width: 200px;
|
||||
background: var(--c-panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
color: var(--ink);
|
||||
border-radius: 10px;
|
||||
padding: .5rem .7rem;
|
||||
box-shadow: var(--shadow);
|
||||
font-weight: 700;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.scheduler-container .controls input[type="text"]:focus-visible,
|
||||
.scheduler-container .pill:focus-visible {
|
||||
outline: 2px solid var(--acid);
|
||||
outline-offset: 2px;
|
||||
box-shadow: 0 0 0 3px color-mix(in oklab, var(--acid) 25%, transparent);
|
||||
}
|
||||
|
||||
.scheduler-container .stats {
|
||||
flex-basis: 100%;
|
||||
margin-left: 0;
|
||||
text-align: center;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
/* Board */
|
||||
.scheduler-container .boardWrap {
|
||||
height: calc(100vh - (var(--h-topbar, 0px) + 5px) - 56px - 52px);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.scheduler-container .board {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
padding: 14px;
|
||||
min-width: 960px;
|
||||
}
|
||||
|
||||
.scheduler-container .lane {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 16px;
|
||||
width: 340px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: var(--shadow);
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.scheduler-container .laneHeader {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: .6rem;
|
||||
padding: .6rem .75rem;
|
||||
border-bottom: 1px solid var(--c-border-strong);
|
||||
border-top-left-radius: 16px;
|
||||
border-top-right-radius: 16px;
|
||||
background: linear-gradient(180deg, color-mix(in oklab, var(--panel) 96%, transparent), color-mix(in oklab, var(--panel) 88%, transparent));
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.scheduler-container .laneHeader .dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 0 0 1px rgba(255, 255, 255, .08) inset;
|
||||
}
|
||||
|
||||
.scheduler-container .laneHeader .count {
|
||||
margin-left: auto;
|
||||
color: var(--muted);
|
||||
font-size: .9rem;
|
||||
}
|
||||
|
||||
.scheduler-container .laneBody {
|
||||
padding: .6rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .6rem;
|
||||
overflow: auto;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* Status dot colors */
|
||||
.scheduler-container .status-upcoming .laneHeader .dot {
|
||||
background: var(--c-upcoming);
|
||||
animation: sched-dotPulse 1.6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.scheduler-container .status-pending .laneHeader .dot {
|
||||
background: var(--c-pending);
|
||||
}
|
||||
|
||||
.scheduler-container .status-running .laneHeader .dot {
|
||||
background: var(--c-running);
|
||||
animation: sched-dotPulse 1.6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.scheduler-container .status-success .laneHeader .dot {
|
||||
background: var(--c-success);
|
||||
}
|
||||
|
||||
.scheduler-container .status-failed .laneHeader .dot {
|
||||
background: var(--c-failed);
|
||||
}
|
||||
|
||||
.scheduler-container .status-expired .laneHeader .dot {
|
||||
background: var(--c-expired);
|
||||
}
|
||||
|
||||
.scheduler-container .status-cancelled .laneHeader .dot {
|
||||
background: var(--c-cancel);
|
||||
}
|
||||
|
||||
@keyframes sched-dotPulse {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 rgba(74, 168, 255, 0);
|
||||
}
|
||||
|
||||
50% {
|
||||
box-shadow: 0 0 12px 3px rgba(74, 168, 255, .65);
|
||||
}
|
||||
}
|
||||
|
||||
/* Cards */
|
||||
.scheduler-container .card {
|
||||
position: relative;
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 12px;
|
||||
padding: .7rem .75rem;
|
||||
box-shadow: var(--shadow);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .45rem;
|
||||
overflow: hidden;
|
||||
transition: transform .15s ease, box-shadow .25s ease, filter .2s ease, background .25s ease;
|
||||
will-change: transform, box-shadow, filter;
|
||||
background: var(--c-panel);
|
||||
}
|
||||
|
||||
.scheduler-container .card:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 16px 36px rgba(0, 0, 0, .4);
|
||||
}
|
||||
|
||||
.scheduler-container .card .infoBtn {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 6px;
|
||||
z-index: 3;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
line-height: 20px;
|
||||
font-weight: 800;
|
||||
text-align: center;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--c-border-strong);
|
||||
background: var(--panel);
|
||||
color: var(--c-upcoming);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.scheduler-container .card .infoBtn:hover {
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
|
||||
/* Card status backgrounds */
|
||||
.scheduler-container .card.status-upcoming {
|
||||
background: color-mix(in oklab, var(--c-upcoming) 12%, var(--c-panel));
|
||||
animation: sched-breathe 2.6s ease-in-out infinite, sched-halo 2.6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.scheduler-container .card.status-pending {
|
||||
background: color-mix(in oklab, var(--c-pending) 10%, var(--c-panel));
|
||||
animation: sched-breathe 2.6s ease-in-out infinite, sched-haloGray 2.8s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.scheduler-container .card.status-running {
|
||||
background: color-mix(in oklab, var(--c-running) 12%, var(--c-panel));
|
||||
animation: sched-pulse 1.8s ease-in-out infinite, sched-haloBlue 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.scheduler-container .card.status-success {
|
||||
background: color-mix(in oklab, var(--c-success) 10%, var(--c-panel));
|
||||
}
|
||||
|
||||
.scheduler-container .card.status-failed {
|
||||
background: color-mix(in oklab, var(--c-failed) 10%, var(--c-panel));
|
||||
}
|
||||
|
||||
.scheduler-container .card.status-expired {
|
||||
background: color-mix(in oklab, var(--c-expired) 10%, var(--c-panel));
|
||||
}
|
||||
|
||||
.scheduler-container .card.status-cancelled {
|
||||
background: color-mix(in oklab, var(--c-cancel) 10%, var(--c-panel));
|
||||
}
|
||||
|
||||
.scheduler-container .badge {
|
||||
margin-left: auto;
|
||||
border-radius: 999px;
|
||||
padding: .15rem .6rem;
|
||||
font-size: .75rem;
|
||||
font-weight: 800;
|
||||
color: #0a0d10;
|
||||
}
|
||||
|
||||
.scheduler-container .card.status-upcoming .badge {
|
||||
background: var(--c-upcoming);
|
||||
}
|
||||
|
||||
.scheduler-container .card.status-pending .badge {
|
||||
background: var(--c-pending);
|
||||
}
|
||||
|
||||
.scheduler-container .card.status-running .badge {
|
||||
background: var(--c-running);
|
||||
}
|
||||
|
||||
.scheduler-container .card.status-success .badge {
|
||||
background: var(--c-success);
|
||||
}
|
||||
|
||||
.scheduler-container .card.status-failed .badge {
|
||||
background: var(--c-failed);
|
||||
}
|
||||
|
||||
.scheduler-container .card.status-expired .badge {
|
||||
background: var(--c-expired);
|
||||
}
|
||||
|
||||
.scheduler-container .card.status-cancelled .badge {
|
||||
background: var(--c-cancel);
|
||||
}
|
||||
|
||||
/* Collapsed */
|
||||
.scheduler-container .card.collapsed .kv,
|
||||
.scheduler-container .card.collapsed .tags,
|
||||
.scheduler-container .card.collapsed .timer,
|
||||
.scheduler-container .card.collapsed .meta,
|
||||
.scheduler-container .card.collapsed .btns,
|
||||
.scheduler-container .card.collapsed .notice {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.scheduler-container .card.collapsed {
|
||||
gap: .25rem;
|
||||
padding: .4rem .5rem;
|
||||
}
|
||||
|
||||
.scheduler-container .card.collapsed .actionIcon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.scheduler-container .cardHeader {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: .6rem;
|
||||
}
|
||||
|
||||
.scheduler-container .actionName {
|
||||
font-weight: 800;
|
||||
letter-spacing: .2px;
|
||||
}
|
||||
|
||||
.scheduler-container .actionIconWrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.scheduler-container .actionIcon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
object-fit: contain;
|
||||
border-radius: 6px;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--c-border);
|
||||
}
|
||||
|
||||
.scheduler-container .card.status-running .actionIcon {
|
||||
animation: sched-pulseIcon 1.2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.scheduler-container .card.status-pending .actionIcon {
|
||||
animation: sched-swayIcon 1.8s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.scheduler-container .card.status-upcoming .actionIcon {
|
||||
animation: sched-blinkIcon 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes sched-pulseIcon {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(1.25);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sched-swayIcon {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
25% {
|
||||
transform: rotate(-5deg);
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: rotate(5deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sched-blinkIcon {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: .4;
|
||||
}
|
||||
}
|
||||
|
||||
.scheduler-container .kv {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .45rem .8rem;
|
||||
font-size: .9rem;
|
||||
}
|
||||
|
||||
.scheduler-container .kv .k {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.scheduler-container .tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .35rem;
|
||||
}
|
||||
|
||||
.scheduler-container .tag {
|
||||
background: var(--panel);
|
||||
color: var(--ink);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
padding: .15rem .45rem;
|
||||
border-radius: 999px;
|
||||
font-size: .74rem;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.scheduler-container .meta {
|
||||
color: color-mix(in oklab, var(--ink) 76%, #9aa7b2);
|
||||
font-size: .82rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .5rem .8rem;
|
||||
}
|
||||
|
||||
.scheduler-container .btns {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .4rem;
|
||||
margin-top: .2rem;
|
||||
}
|
||||
|
||||
.scheduler-container .btn {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
color: var(--ink);
|
||||
padding: .35rem .6rem;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.scheduler-container .btn:hover {
|
||||
filter: brightness(1.08);
|
||||
}
|
||||
|
||||
.scheduler-container .btn.danger {
|
||||
background: color-mix(in oklab, #9c2b2b 22%, var(--panel));
|
||||
border-color: #4a1515;
|
||||
color: #ffd0d0;
|
||||
}
|
||||
|
||||
.scheduler-container .btn.warn {
|
||||
background: color-mix(in oklab, #9c6a2b 22%, var(--panel));
|
||||
border-color: #5c2c0c;
|
||||
color: #ffd8a8;
|
||||
}
|
||||
|
||||
.scheduler-container .empty {
|
||||
color: var(--muted);
|
||||
text-align: center;
|
||||
padding: .6rem;
|
||||
}
|
||||
|
||||
@keyframes sched-pulse {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sched-breathe {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
filter: brightness(1);
|
||||
}
|
||||
|
||||
50% {
|
||||
filter: brightness(1.07);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sched-halo {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 0 12px rgba(156, 194, 255, .25);
|
||||
}
|
||||
|
||||
50% {
|
||||
box-shadow: 0 0 22px rgba(156, 194, 255, .45);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sched-haloGray {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 0 12px rgba(187, 187, 187, .15);
|
||||
}
|
||||
|
||||
50% {
|
||||
box-shadow: 0 0 22px rgba(187, 187, 187, .3);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sched-haloBlue {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 0 12px rgba(74, 168, 255, .25);
|
||||
}
|
||||
|
||||
50% {
|
||||
box-shadow: 0 0 26px rgba(74, 168, 255, .5);
|
||||
}
|
||||
}
|
||||
|
||||
/* Timer / Progress */
|
||||
.scheduler-container .timer {
|
||||
font-size: .82rem;
|
||||
color: color-mix(in oklab, var(--ink) 80%, #bcd7ff);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: .4rem;
|
||||
}
|
||||
|
||||
.scheduler-container .timer .cd {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.scheduler-container .progress {
|
||||
height: 6px;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 999px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.scheduler-container .progress .bar {
|
||||
height: 100%;
|
||||
width: 0%;
|
||||
background: linear-gradient(90deg, var(--c-running), #00d8ff);
|
||||
}
|
||||
|
||||
/* More button */
|
||||
.scheduler-container .moreWrap {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.scheduler-container .moreBtn {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
color: var(--ink);
|
||||
border-radius: 10px;
|
||||
padding: .45rem .8rem;
|
||||
cursor: pointer;
|
||||
transition: transform .15s;
|
||||
margin: .25rem auto 0;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.scheduler-container .moreBtn:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* Notice */
|
||||
.scheduler-container .notice {
|
||||
padding: .6rem .8rem;
|
||||
color: #ffd9d6;
|
||||
background: color-mix(in oklab, #7a3838 55%, var(--panel));
|
||||
border-bottom: 1px solid #7a3838;
|
||||
display: none;
|
||||
border-radius: 12px;
|
||||
margin: .6rem;
|
||||
}
|
||||
|
||||
/* Chips */
|
||||
.scheduler-container .chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .35rem;
|
||||
margin: .1rem 0 .2rem;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.scheduler-container .chip {
|
||||
--h: 200;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: .4rem;
|
||||
padding: .25rem .55rem;
|
||||
border-radius: 999px;
|
||||
font-size: .82rem;
|
||||
font-weight: 800;
|
||||
color: #fff;
|
||||
letter-spacing: .2px;
|
||||
background: linear-gradient(135deg, rgba(255, 255, 255, .06), rgba(0, 0, 0, .12)), hsl(var(--h), 65%, 34%);
|
||||
border: 1px solid hsla(var(--h), 70%, 60%, .35);
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, .22), inset 0 1px 0 rgba(255, 255, 255, .06);
|
||||
transition: transform .15s ease, box-shadow .2s ease, filter .2s ease;
|
||||
}
|
||||
|
||||
.scheduler-container .chip:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 22px rgba(0, 0, 0, .28);
|
||||
}
|
||||
|
||||
.scheduler-container .chip .k {
|
||||
opacity: .85;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* History modal */
|
||||
.scheduler-container .modalOverlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, .5);
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.scheduler-container .modal {
|
||||
width: min(860px, 92vw);
|
||||
max-height: 80vh;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 20px 56px rgba(0, 0, 0, .6);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.scheduler-container .modalHeader {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: .6rem;
|
||||
padding: .6rem .8rem;
|
||||
border-bottom: 1px solid var(--c-border-strong);
|
||||
background: linear-gradient(180deg, color-mix(in oklab, var(--panel) 96%, transparent), color-mix(in oklab, var(--panel) 88%, transparent));
|
||||
}
|
||||
|
||||
.scheduler-container .modalHeader .title {
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.scheduler-container .modalHeader .spacer {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.scheduler-container .modalBody {
|
||||
padding: .6rem .8rem;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .35rem;
|
||||
}
|
||||
|
||||
.scheduler-container .modalFooter {
|
||||
padding: .5rem .8rem;
|
||||
border-top: 1px solid var(--c-border-strong);
|
||||
display: flex;
|
||||
gap: .5rem;
|
||||
justify-content: flex-end;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.scheduler-container .xBtn,
|
||||
.scheduler-container .miniToggle {
|
||||
background: var(--panel);
|
||||
color: var(--ink);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: 8px;
|
||||
padding: .35rem .6rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.scheduler-container .xBtn:hover,
|
||||
.scheduler-container .miniToggle:hover {
|
||||
filter: brightness(1.08);
|
||||
}
|
||||
|
||||
.scheduler-container #searchBox {
|
||||
width: 100%;
|
||||
background: var(--c-panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
color: var(--ink);
|
||||
border-radius: 10px;
|
||||
padding: .5rem .7rem;
|
||||
box-shadow: var(--shadow);
|
||||
font-weight: 700;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.scheduler-container .histRow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: .6rem;
|
||||
padding: .45rem .6rem;
|
||||
border-radius: 10px;
|
||||
border: 1px solid var(--c-border-strong);
|
||||
background: color-mix(in oklab, var(--ink) 2%, var(--panel));
|
||||
}
|
||||
|
||||
.scheduler-container .histRow .ts {
|
||||
color: var(--muted);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.scheduler-container .histRow .st {
|
||||
font-weight: 900;
|
||||
margin-left: auto;
|
||||
padding: .1rem .5rem;
|
||||
border-radius: 999px;
|
||||
font-size: .75rem;
|
||||
color: #0a0d10;
|
||||
}
|
||||
|
||||
.scheduler-container .hist-success {
|
||||
background: color-mix(in oklab, var(--c-success) 8%, var(--panel));
|
||||
border-left: 3px solid var(--c-success);
|
||||
}
|
||||
|
||||
.scheduler-container .hist-failed {
|
||||
background: color-mix(in oklab, var(--c-failed) 8%, var(--panel));
|
||||
border-left: 3px solid var(--c-failed);
|
||||
}
|
||||
|
||||
.scheduler-container .hist-running {
|
||||
background: color-mix(in oklab, var(--c-running) 8%, var(--panel));
|
||||
border-left: 3px solid var(--c-running);
|
||||
}
|
||||
|
||||
.scheduler-container .hist-pending,
|
||||
.scheduler-container .hist-scheduled {
|
||||
background: color-mix(in oklab, var(--c-pending) 8%, var(--panel));
|
||||
border-left: 3px solid var(--c-pending);
|
||||
}
|
||||
|
||||
.scheduler-container .hist-expired {
|
||||
background: color-mix(in oklab, var(--c-expired) 8%, var(--panel));
|
||||
border-left: 3px solid var(--c-expired);
|
||||
}
|
||||
|
||||
.scheduler-container .hist-cancelled {
|
||||
background: color-mix(in oklab, var(--c-cancel) 8%, var(--panel));
|
||||
border-left: 3px solid var(--c-cancel);
|
||||
}
|
||||
|
||||
.scheduler-container .hist-superseded {
|
||||
background: color-mix(in oklab, var(--c-super) 8%, var(--panel));
|
||||
border-left: 3px solid var(--c-super);
|
||||
}
|
||||
|
||||
@media (max-width:920px) {
|
||||
.scheduler-container .board {
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.scheduler-container .lane {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.scheduler-container .stats {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.scheduler-container .boardWrap {
|
||||
height: auto;
|
||||
min-height: calc(100vh - (var(--h-topbar, 0px) + 5px));
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
|
||||
.scheduler-container .card,
|
||||
.scheduler-container .laneHeader .dot {
|
||||
animation: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
366
web/css/pages/sentinel.css
Normal file
366
web/css/pages/sentinel.css
Normal file
@@ -0,0 +1,366 @@
|
||||
/* ============================================================
|
||||
Sentinel Watchdog — SPA page styles
|
||||
============================================================ */
|
||||
|
||||
.sentinel-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
gap: 12px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
/* ── Header bar ─────────────────────────────────────────── */
|
||||
|
||||
.sentinel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.sentinel-title {
|
||||
margin: 0;
|
||||
font-size: 1.3rem;
|
||||
font-weight: 800;
|
||||
color: var(--ink);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.sentinel-title-icon {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.sentinel-controls {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sentinel-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 14px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--c-border);
|
||||
background: var(--c-panel);
|
||||
font-size: 0.8rem;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.sentinel-toggle.active {
|
||||
border-color: var(--acid);
|
||||
background: rgba(0, 255, 154, 0.08);
|
||||
color: var(--acid);
|
||||
box-shadow: 0 0 12px rgba(0, 255, 154, 0.15);
|
||||
}
|
||||
|
||||
.sentinel-toggle .dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--muted-off);
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.sentinel-toggle.active .dot {
|
||||
background: var(--acid);
|
||||
box-shadow: 0 0 6px var(--acid);
|
||||
animation: sentinel-pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes sentinel-pulse {
|
||||
0%, 100% { opacity: 0.7; box-shadow: 0 0 4px var(--acid); }
|
||||
50% { opacity: 1; box-shadow: 0 0 12px var(--acid); }
|
||||
}
|
||||
|
||||
/* ── Stats bar ──────────────────────────────────────────── */
|
||||
|
||||
.sentinel-stats {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.sentinel-stat {
|
||||
flex: 1 1 120px;
|
||||
padding: 10px 14px;
|
||||
background: var(--grad-card);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.sentinel-stat-val {
|
||||
font-size: 1.4rem;
|
||||
font-weight: 800;
|
||||
font-family: 'Fira Code', monospace;
|
||||
color: var(--ink);
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.sentinel-stat-lbl {
|
||||
font-size: 0.65rem;
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* ── Main grid ──────────────────────────────────────────── */
|
||||
|
||||
.sentinel-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 340px;
|
||||
gap: 12px;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* ── Panels ─────────────────────────────────────────────── */
|
||||
|
||||
.sentinel-panel {
|
||||
background: var(--grad-card);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.sentinel-panel-head {
|
||||
padding: 10px 14px;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
border-bottom: 1px solid var(--c-border);
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sentinel-panel-body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
/* ── Event cards ────────────────────────────────────────── */
|
||||
|
||||
.sentinel-event {
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
border-left: 3px solid var(--c-border);
|
||||
background: color-mix(in oklab, var(--c-panel) 80%, transparent);
|
||||
transition: background 0.15s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sentinel-event:hover {
|
||||
background: color-mix(in oklab, var(--c-panel) 100%, transparent);
|
||||
}
|
||||
|
||||
.sentinel-event.unread {
|
||||
border-left-color: var(--acid);
|
||||
}
|
||||
|
||||
.sentinel-event.sev-warning {
|
||||
border-left-color: var(--warning);
|
||||
}
|
||||
|
||||
.sentinel-event.sev-critical {
|
||||
border-left-color: var(--danger);
|
||||
}
|
||||
|
||||
.sentinel-event-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.sentinel-event-title {
|
||||
font-size: 0.82rem;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sentinel-event-time {
|
||||
font-size: 0.65rem;
|
||||
color: var(--muted);
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sentinel-event-body {
|
||||
font-size: 0.72rem;
|
||||
color: var(--muted);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.sentinel-event-badge {
|
||||
display: inline-block;
|
||||
padding: 1px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.6rem;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.5px;
|
||||
text-transform: uppercase;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.sentinel-event-badge.new_device { background: rgba(0,220,255,0.15); color: #00dcff; }
|
||||
.sentinel-event-badge.device_join { background: rgba(0,255,160,0.15); color: #00ffa0; }
|
||||
.sentinel-event-badge.device_leave { background: rgba(255,255,255,0.08); color: #888; }
|
||||
.sentinel-event-badge.arp_spoof { background: rgba(255,59,59,0.15); color: #ff3b3b; }
|
||||
.sentinel-event-badge.port_change { background: rgba(255,209,102,0.15); color: #ffd166; }
|
||||
.sentinel-event-badge.mac_flood { background: rgba(255,59,59,0.2); color: #ff3b3b; }
|
||||
.sentinel-event-badge.rogue_dhcp { background: rgba(255,100,180,0.15); color: #ff64b4; }
|
||||
.sentinel-event-badge.dns_anomaly { background: rgba(180,140,255,0.15); color: #b48cff; }
|
||||
|
||||
/* ── Sidebar tabs ───────────────────────────────────────── */
|
||||
|
||||
.sentinel-side-tabs {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
padding: 6px;
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
border-bottom: 1px solid var(--c-border);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sentinel-side-tab {
|
||||
flex: 1;
|
||||
padding: 5px 8px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
transition: 0.15s;
|
||||
}
|
||||
|
||||
.sentinel-side-tab.active {
|
||||
background: var(--c-panel);
|
||||
color: var(--acid);
|
||||
}
|
||||
|
||||
/* ── Rules list ─────────────────────────────────────────── */
|
||||
|
||||
.sentinel-rule {
|
||||
padding: 8px 10px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--c-border);
|
||||
background: color-mix(in oklab, var(--c-panel) 60%, transparent);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.sentinel-rule-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.sentinel-rule-name {
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.sentinel-rule-type {
|
||||
font-size: 0.65rem;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.sentinel-rule-actions {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* ── Notifiers config ───────────────────────────────────── */
|
||||
|
||||
.sentinel-notifier-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
padding: 8px 10px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--c-border);
|
||||
background: color-mix(in oklab, var(--c-panel) 60%, transparent);
|
||||
}
|
||||
|
||||
.sentinel-notifier-label {
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.sentinel-notifier-input {
|
||||
width: 100%;
|
||||
padding: 6px 8px;
|
||||
background: var(--c-panel);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 6px;
|
||||
color: var(--ink);
|
||||
font-size: 0.75rem;
|
||||
font-family: 'Fira Code', monospace;
|
||||
}
|
||||
|
||||
/* ── Responsive ─────────────────────────────────────────── */
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.sentinel-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.sentinel-stats {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.sentinel-stat {
|
||||
flex: 1 1 80px;
|
||||
min-width: 70px;
|
||||
padding: 8px 10px;
|
||||
}
|
||||
|
||||
.sentinel-stat-val {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.sentinel-page {
|
||||
padding: 10px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.sentinel-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
217
web/css/pages/shared.css
Normal file
217
web/css/pages/shared.css
Normal file
@@ -0,0 +1,217 @@
|
||||
/* ==========================================================================
|
||||
pages.css — Page-specific styles for all SPA page modules.
|
||||
Each section is scoped under the page's wrapper class to avoid conflicts.
|
||||
========================================================================== */
|
||||
|
||||
/* ===== Page-specific variables (extends global.css tokens) ===== */
|
||||
:root {
|
||||
/* Bridge aliases used by multiple pages (Credentials, Loot, Files, Attacks) */
|
||||
--_bg: var(--bg);
|
||||
--_panel: var(--c-panel-2);
|
||||
--_panel-hi: color-mix(in oklab, var(--c-panel-2) 96%, transparent);
|
||||
--_panel-lo: color-mix(in oklab, var(--c-panel-2) 86%, transparent);
|
||||
--_border: var(--c-border);
|
||||
--_ink: var(--ink);
|
||||
--_muted: var(--muted);
|
||||
--_acid: var(--acid);
|
||||
--_acid2: var(--acid-2);
|
||||
--_shadow: var(--shadow);
|
||||
|
||||
/* NetKB chip colors */
|
||||
--kb-hostname-bg: color-mix(in oklab, var(--acid) 16%, transparent);
|
||||
--kb-ip-bg: color-mix(in oklab, var(--acid-2) 18%, transparent);
|
||||
--kb-mac-bg: color-mix(in oklab, var(--muted) 10%, transparent);
|
||||
--kb-vendor-bg: color-mix(in oklab, #b18cff 16%, transparent);
|
||||
--kb-ports-bg: color-mix(in oklab, #5fd1ff 16%, transparent);
|
||||
--kb-essid-bg: color-mix(in oklab, #00e6c3 16%, transparent);
|
||||
--kb-offline-bg: color-mix(in oklab, var(--bg-2) 88%, black 12%);
|
||||
--kb-offline-brd: color-mix(in oklab, var(--c-border-strong) 60%, transparent);
|
||||
--kb-offline-ring: color-mix(in oklab, #ff5b5b 30%, transparent);
|
||||
--kb-badge-shimmer: linear-gradient(90deg, transparent, rgba(255, 255, 255, .22), transparent);
|
||||
|
||||
/* Attacks page */
|
||||
--tile-min: 160px;
|
||||
--ok-glow: rgba(34, 197, 94, .45);
|
||||
--ko-glow: rgba(239, 68, 68, .45);
|
||||
}
|
||||
|
||||
/* ===== Shared sidebar layout (SPA parity with web_old) ===== */
|
||||
.page-with-sidebar {
|
||||
--page-sidebar-w: 280px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
min-height: calc(100vh - var(--h-topbar, 56px) - var(--h-bottombar, 56px) - 24px);
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.page-with-sidebar .page-sidebar {
|
||||
width: var(--page-sidebar-w);
|
||||
flex: 0 0 var(--page-sidebar-w);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
align-self: flex-start;
|
||||
max-height: calc(100vh - var(--h-topbar, 56px) - var(--h-bottombar, 56px) - 24px);
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 12px;
|
||||
background: var(--grad-card);
|
||||
box-shadow: var(--shadow);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.page-with-sidebar .page-main {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.page-with-sidebar .sidebar-toggle-btn {
|
||||
display: inline-flex;
|
||||
margin-bottom: 0;
|
||||
align-self: auto;
|
||||
}
|
||||
|
||||
.page-with-sidebar .sidebar-fab {
|
||||
position: fixed;
|
||||
right: 14px;
|
||||
bottom: calc(var(--h-bottombar, 56px) + 14px);
|
||||
z-index: 82;
|
||||
border-radius: 999px;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
min-width: 38px;
|
||||
min-height: 38px;
|
||||
padding: 0;
|
||||
font-size: 16px;
|
||||
color: var(--ink);
|
||||
background: color-mix(in oklab, var(--c-panel) 88%, transparent);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, .28);
|
||||
opacity: .88;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.page-with-sidebar .sidebar-fab:hover {
|
||||
opacity: 1;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.page-with-sidebar .sidebar-fab:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.page-sidebar-backdrop {
|
||||
display: none;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: var(--h-topbar, 56px);
|
||||
bottom: var(--h-bottombar, 56px);
|
||||
background: rgba(0, 0, 0, .52);
|
||||
border: 0;
|
||||
z-index: 79;
|
||||
}
|
||||
|
||||
.page-with-sidebar .sidehead {
|
||||
padding: 10px;
|
||||
border-bottom: 1px dashed var(--c-border);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 5;
|
||||
background: var(--grad-card);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.page-with-sidebar .sidetitle {
|
||||
font-weight: 800;
|
||||
color: var(--acid);
|
||||
letter-spacing: .05em;
|
||||
}
|
||||
|
||||
.page-with-sidebar .sidecontent {
|
||||
padding: 10px;
|
||||
overflow: auto;
|
||||
min-height: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.page-with-sidebar.sidebar-collapsed .page-sidebar {
|
||||
width: 0;
|
||||
flex-basis: 0;
|
||||
padding: 0;
|
||||
border-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.page-with-sidebar {
|
||||
min-height: calc(100vh - var(--h-topbar, 56px) - var(--h-bottombar, 56px) - 12px);
|
||||
}
|
||||
|
||||
.page-with-sidebar .sidebar-fab {
|
||||
right: 10px;
|
||||
bottom: calc(var(--h-bottombar, 56px) + 10px);
|
||||
}
|
||||
|
||||
.sidebar-fab-unified {
|
||||
position: fixed;
|
||||
z-index: 82;
|
||||
border-radius: 999px;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
min-width: 38px;
|
||||
min-height: 38px;
|
||||
padding: 0;
|
||||
font-size: 16px;
|
||||
color: var(--ink);
|
||||
background: color-mix(in oklab, var(--c-panel) 88%, transparent);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, .28);
|
||||
opacity: .88;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.sidebar-fab-unified:hover {
|
||||
opacity: 1;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.sidebar-fab-unified:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.page-with-sidebar .page-sidebar {
|
||||
position: fixed;
|
||||
top: var(--h-topbar, 56px);
|
||||
bottom: var(--h-bottombar, 56px);
|
||||
left: 0;
|
||||
z-index: 80;
|
||||
width: min(86vw, 320px);
|
||||
flex-basis: auto;
|
||||
transform: translateX(-105%);
|
||||
transition: transform .2s ease;
|
||||
}
|
||||
|
||||
.page-with-sidebar.sidebar-open .page-sidebar {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.page-with-sidebar.sidebar-open .page-sidebar-backdrop {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
698
web/css/pages/vulnerabilities.css
Normal file
698
web/css/pages/vulnerabilities.css
Normal file
@@ -0,0 +1,698 @@
|
||||
/* ==========================================================================
|
||||
VULNERABILITIES
|
||||
========================================================================== */
|
||||
.vuln-container {
|
||||
padding: var(--gap-4);
|
||||
min-height: calc(100vh - var(--h-topbar) - var(--h-bottombar));
|
||||
animation: vuln-fadeIn 0.5s ease-in;
|
||||
}
|
||||
|
||||
@keyframes vuln-fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.vuln-container .stats-header {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
gap: var(--gap-4);
|
||||
margin-bottom: var(--gap-3);
|
||||
}
|
||||
|
||||
.vuln-container .stat-card {
|
||||
background: var(--grad-card);
|
||||
border-radius: var(--radius);
|
||||
padding: var(--gap-4);
|
||||
text-align: center;
|
||||
border: 1px solid var(--c-border);
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
box-shadow: var(--elev);
|
||||
}
|
||||
|
||||
.vuln-container .stat-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, var(--accent), var(--accent-2));
|
||||
animation: vuln-pulse 2s infinite;
|
||||
}
|
||||
|
||||
.vuln-container .stat-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--shadow-hover);
|
||||
}
|
||||
|
||||
.vuln-container .stat-number {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
background: linear-gradient(90deg, var(--accent), var(--accent-2));
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.vuln-container .stat-label {
|
||||
font-size: 12px;
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.vuln-container .control-bar {
|
||||
background: var(--grad-card);
|
||||
border-radius: var(--radius);
|
||||
padding: var(--gap-4);
|
||||
margin-bottom: var(--gap-3);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--gap-3);
|
||||
align-items: center;
|
||||
border: 1px solid var(--c-border);
|
||||
box-shadow: var(--elev);
|
||||
}
|
||||
|
||||
.vuln-container .search-box {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.vuln-container .search-input {
|
||||
width: 100%;
|
||||
height: var(--control-h);
|
||||
padding: 0 40px 0 var(--control-pad-x);
|
||||
background: var(--c-panel);
|
||||
border: 1px solid var(--c-border-strong);
|
||||
border-radius: var(--control-r);
|
||||
color: var(--ink);
|
||||
font-size: 14px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.vuln-container .search-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 0 0 3px var(--glow-weak);
|
||||
}
|
||||
|
||||
.vuln-container .clear-search {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--danger);
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
display: none;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.vuln-container .clear-search:hover {
|
||||
color: var(--acid-2);
|
||||
}
|
||||
|
||||
.vuln-container .clear-search.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.vuln-container .filter-buttons {
|
||||
display: flex;
|
||||
gap: var(--gap-3);
|
||||
}
|
||||
|
||||
.vuln-container .filter-btn.active {
|
||||
background: linear-gradient(90deg, var(--accent), var(--accent-2));
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.vuln-container .severity-filter {
|
||||
display: flex;
|
||||
gap: var(--gap-2);
|
||||
}
|
||||
|
||||
.vuln-container .severity-btn.critical.active {
|
||||
background: var(--danger);
|
||||
border-color: var(--danger);
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
.vuln-container .severity-btn.high.active {
|
||||
background: var(--warning);
|
||||
border-color: var(--warning);
|
||||
color: var(--ink-invert);
|
||||
}
|
||||
|
||||
.vuln-container .severity-btn.medium.active {
|
||||
background: var(--accent-2);
|
||||
border-color: var(--accent-2);
|
||||
color: var(--ink-invert);
|
||||
}
|
||||
|
||||
.vuln-container .severity-btn.low.active {
|
||||
background: var(--ok);
|
||||
border-color: var(--ok);
|
||||
color: var(--ink-invert);
|
||||
}
|
||||
|
||||
.vuln-container .vuln-grid {
|
||||
display: grid;
|
||||
gap: var(--gap-4);
|
||||
max-height: calc(100vh - 250px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.vuln-container .vuln-card {
|
||||
background: var(--grad-card);
|
||||
border-radius: var(--radius);
|
||||
border: 1px solid var(--c-border);
|
||||
overflow: hidden;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
animation: vuln-slideIn 0.4s ease-out;
|
||||
box-shadow: var(--elev);
|
||||
}
|
||||
|
||||
@keyframes vuln-slideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
.vuln-container .vuln-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--shadow-hover);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.vuln-container .vuln-card.inactive {
|
||||
opacity: 0.6;
|
||||
border-color: var(--muted-off);
|
||||
}
|
||||
|
||||
.vuln-container .vuln-header {
|
||||
padding: var(--gap-4);
|
||||
background: var(--grad-quickpanel);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
border-bottom: 1px solid var(--c-border);
|
||||
}
|
||||
|
||||
.vuln-container .vuln-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--gap-3);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.vuln-container .vuln-id {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
background: linear-gradient(90deg, var(--accent), var(--accent-2));
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.vuln-container .severity-badge {
|
||||
padding: 4px 10px;
|
||||
border-radius: 20px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
animation: vuln-pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes vuln-pulse {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.vuln-container .severity-critical {
|
||||
background: var(--danger);
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
.vuln-container .severity-high {
|
||||
background: var(--warning);
|
||||
color: var(--ink-invert);
|
||||
}
|
||||
|
||||
.vuln-container .severity-medium {
|
||||
background: var(--accent-2);
|
||||
color: var(--ink-invert);
|
||||
}
|
||||
|
||||
.vuln-container .severity-low {
|
||||
background: var(--ok);
|
||||
color: var(--ink-invert);
|
||||
}
|
||||
|
||||
.vuln-container .vuln-meta {
|
||||
display: flex;
|
||||
gap: var(--gap-4);
|
||||
font-size: 12px;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.vuln-container .meta-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--gap-2);
|
||||
}
|
||||
|
||||
.vuln-container .expand-icon {
|
||||
color: var(--muted);
|
||||
transition: transform 0.3s ease;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.vuln-container .vuln-card.expanded .expand-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.vuln-container .vuln-content {
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease-out;
|
||||
}
|
||||
|
||||
.vuln-container .vuln-card.expanded .vuln-content {
|
||||
max-height: 1000px;
|
||||
}
|
||||
|
||||
.vuln-container .vuln-details {
|
||||
padding: var(--gap-4);
|
||||
border-top: 1px solid var(--c-border);
|
||||
background: var(--c-panel);
|
||||
}
|
||||
|
||||
.vuln-container .detail-section {
|
||||
margin-bottom: var(--gap-4);
|
||||
}
|
||||
|
||||
.vuln-container .detail-title {
|
||||
font-size: 12px;
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
margin-bottom: var(--gap-2);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.vuln-container .detail-content {
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.vuln-container .tags-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--gap-2);
|
||||
}
|
||||
|
||||
.vuln-container .tag {
|
||||
padding: 4px 8px;
|
||||
background: var(--c-chip-bg);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: var(--gap-2);
|
||||
font-size: 11px;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.vuln-container .action-buttons {
|
||||
display: flex;
|
||||
gap: var(--gap-3);
|
||||
padding: var(--gap-4);
|
||||
border-top: 1px solid var(--c-border);
|
||||
background: var(--c-panel-2);
|
||||
}
|
||||
|
||||
.vuln-container .action-btn {
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.vuln-container .btn-remediate {
|
||||
background: var(--ok);
|
||||
border-color: var(--ok);
|
||||
color: var(--ink-invert);
|
||||
}
|
||||
|
||||
.vuln-container .btn-details {
|
||||
background: var(--accent-2);
|
||||
border-color: var(--accent-2);
|
||||
color: var(--ink-invert);
|
||||
}
|
||||
|
||||
.vuln-container .btn-export {
|
||||
background: linear-gradient(90deg, var(--accent), var(--accent-2));
|
||||
border-color: var(--accent);
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
/* Host view */
|
||||
.vuln-container .host-card {
|
||||
background: var(--grad-card);
|
||||
border-radius: var(--radius);
|
||||
border: 1px solid var(--c-border);
|
||||
margin-bottom: var(--gap-4);
|
||||
overflow: hidden;
|
||||
animation: vuln-slideIn 0.4s ease-out;
|
||||
box-shadow: var(--elev);
|
||||
}
|
||||
|
||||
.vuln-container .host-header {
|
||||
background: var(--grad-quickpanel);
|
||||
padding: var(--gap-4);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--c-border);
|
||||
}
|
||||
|
||||
.vuln-container .host-header:hover {
|
||||
background: var(--grad-modal);
|
||||
}
|
||||
|
||||
.vuln-container .host-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--gap-2);
|
||||
}
|
||||
|
||||
.vuln-container .host-name {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: var(--ink);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--gap-3);
|
||||
}
|
||||
|
||||
.vuln-container .host-details {
|
||||
display: flex;
|
||||
gap: var(--gap-4);
|
||||
font-size: 12px;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.vuln-container .host-stats {
|
||||
display: flex;
|
||||
gap: var(--gap-3);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.vuln-container .host-stat-badge {
|
||||
padding: 5px 10px;
|
||||
border-radius: 20px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--gap-2);
|
||||
}
|
||||
|
||||
.vuln-container .host-vulns {
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease-out;
|
||||
}
|
||||
|
||||
.vuln-container .host-card.expanded .host-vulns {
|
||||
max-height: 2000px;
|
||||
}
|
||||
|
||||
.vuln-container .host-vuln-list {
|
||||
padding: var(--gap-4);
|
||||
background: var(--c-panel);
|
||||
}
|
||||
|
||||
.vuln-container .host-vuln-item {
|
||||
background: var(--c-panel-2);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: var(--control-r);
|
||||
padding: var(--gap-3);
|
||||
margin-bottom: var(--gap-3);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.vuln-container .host-vuln-item:hover {
|
||||
background: var(--grad-card);
|
||||
border-color: var(--accent);
|
||||
transform: translateX(5px);
|
||||
}
|
||||
|
||||
.vuln-container .host-summary {
|
||||
background: var(--grad-quickpanel);
|
||||
padding: var(--gap-3);
|
||||
border-radius: var(--control-r);
|
||||
margin-bottom: var(--gap-3);
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.vuln-container .host-summary-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--gap-2);
|
||||
}
|
||||
|
||||
.vuln-container .host-summary-value {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
background: linear-gradient(90deg, var(--accent), var(--accent-2));
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.vuln-container .host-summary-label {
|
||||
font-size: 10px;
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
/* Badges */
|
||||
.vuln-container .badge-kev {
|
||||
background: var(--danger);
|
||||
padding: 2px 6px;
|
||||
border-radius: 10px;
|
||||
font-size: 10px;
|
||||
color: var(--white);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.vuln-container .badge-exploit {
|
||||
background: linear-gradient(135deg, #9c27b0, #e1bee7);
|
||||
padding: 2px 6px;
|
||||
border-radius: 10px;
|
||||
font-size: 10px;
|
||||
color: var(--white);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.vuln-container .badge-epss-high {
|
||||
background: linear-gradient(135deg, var(--danger), var(--warning));
|
||||
padding: 2px 6px;
|
||||
border-radius: 10px;
|
||||
font-size: 10px;
|
||||
color: var(--white);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.vuln-container .badge-epss-medium {
|
||||
background: linear-gradient(135deg, var(--warning), var(--accent-2));
|
||||
padding: 2px 6px;
|
||||
border-radius: 10px;
|
||||
font-size: 10px;
|
||||
color: var(--white);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Pagination */
|
||||
.vuln-container .pagination {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: var(--gap-3);
|
||||
margin-top: var(--gap-4);
|
||||
padding: var(--gap-3);
|
||||
}
|
||||
|
||||
.vuln-container .page-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.vuln-container .page-btn.active {
|
||||
background: linear-gradient(90deg, var(--accent), var(--accent-2));
|
||||
border-color: var(--accent);
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
.vuln-container .page-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* Modal */
|
||||
.vuln-container .modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--glass-8);
|
||||
z-index: 1000;
|
||||
animation: vuln-fadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
.vuln-container .modal.show {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.vuln-container .modal-content {
|
||||
background: var(--grad-modal);
|
||||
border-radius: var(--radius);
|
||||
max-width: 800px;
|
||||
width: 90%;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
animation: vuln-slideUp 0.3s ease;
|
||||
border: 1px solid var(--c-border-strong);
|
||||
box-shadow: var(--shadow-hover);
|
||||
}
|
||||
|
||||
@keyframes vuln-slideUp {
|
||||
from {
|
||||
transform: translateY(50px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.vuln-container .modal-header {
|
||||
padding: var(--gap-4);
|
||||
border-bottom: 1px solid var(--c-border);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: var(--grad-quickpanel);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.vuln-container .modal-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
background: linear-gradient(90deg, var(--accent), var(--accent-2));
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.vuln-container .close-modal {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--muted);
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.vuln-container .close-modal:hover {
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.vuln-container .modal-body {
|
||||
padding: var(--gap-4);
|
||||
}
|
||||
|
||||
@media (max-width:768px) {
|
||||
.vuln-container .stats-header {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.vuln-container .control-bar {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.vuln-container .search-box {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.vuln-container .filter-buttons {
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.vuln-container .severity-filter {
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.vuln-container .vuln-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: var(--gap-3);
|
||||
}
|
||||
|
||||
.vuln-container .vuln-meta {
|
||||
flex-direction: column;
|
||||
gap: var(--gap-2);
|
||||
}
|
||||
|
||||
.vuln-container .modal-content {
|
||||
width: 95%;
|
||||
max-height: 90vh;
|
||||
}
|
||||
}
|
||||
|
||||
493
web/css/pages/zombieland.css
Normal file
493
web/css/pages/zombieland.css
Normal file
@@ -0,0 +1,493 @@
|
||||
/* ==========================================================================
|
||||
ZOMBIELAND (C2 Module) CSS
|
||||
========================================================================== */
|
||||
|
||||
/* Main layout constraints */
|
||||
.zombieland-container.page-with-sidebar {
|
||||
height: calc(100vh - var(--h-topbar, 56px) - var(--h-bottombar, 56px) - 24px);
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.zl-sidebar.page-sidebar {
|
||||
width: 260px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--grad-card);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 12px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.zl-main.page-main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
/* Sidebar structure */
|
||||
.zl-stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 8px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border: 1px solid var(--c-border);
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.stat-item .stat-value {
|
||||
font-weight: bold;
|
||||
color: var(--acid);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.stat-item .stat-label {
|
||||
font-size: 0.8rem;
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.zl-toolbar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
/* Modals */
|
||||
.modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: var(--grad-card);
|
||||
border: 1px solid var(--c-border);
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
/* Main Grid Layout */
|
||||
.zl-main-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
|
||||
gap: 12px;
|
||||
flex: 1;
|
||||
/* Takes available space except logs */
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.zl-console-panel,
|
||||
.zl-agents-panel,
|
||||
.zl-logs-panel {
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 12px;
|
||||
background: var(--c-panel);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Log Panel underneath */
|
||||
.zl-logs-panel {
|
||||
height: 150px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.zl-panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-bottom: 1px solid var(--c-border);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.zl-panel-title {
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
color: var(--acid);
|
||||
}
|
||||
|
||||
.zl-quickbar {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.quick-cmd {
|
||||
background: transparent;
|
||||
border: 1px solid var(--c-border-strong);
|
||||
color: var(--muted);
|
||||
font-size: 0.7rem;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.quick-cmd:hover {
|
||||
color: var(--acid);
|
||||
border-color: var(--acid);
|
||||
}
|
||||
|
||||
.zl-console-output,
|
||||
.zl-logs-output {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
font-family: 'Fira Code', monospace;
|
||||
font-size: 0.8rem;
|
||||
background: #020406;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* Controls */
|
||||
.zl-console-input-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
border-top: 1px solid var(--c-border);
|
||||
background: var(--c-panel-2);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.zl-target-select,
|
||||
.zl-cmd-input,
|
||||
.zl-search-input {
|
||||
background: #000;
|
||||
color: #fff;
|
||||
border: 1px solid var(--c-border-strong);
|
||||
padding: 6px 10px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.zl-cmd-input {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.zl-toolbar-left {
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
max-width: 200px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.zl-search-input {
|
||||
width: 100%;
|
||||
border-radius: 6px;
|
||||
padding: 4px 20px 4px 8px;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.zl-search-clear {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
color: var(--muted);
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.zl-agents-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* Agent Card Styles */
|
||||
.zl-agent-card {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 8px;
|
||||
padding: 8px 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
transition: 0.2s ease-out;
|
||||
}
|
||||
|
||||
.zl-agent-card.selected {
|
||||
border-color: var(--acid);
|
||||
background: rgba(0, 255, 160, 0.05);
|
||||
}
|
||||
|
||||
.zl-agent-card:hover {
|
||||
border-color: var(--c-border-hi);
|
||||
}
|
||||
|
||||
.zl-card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.zl-card-identity {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.zl-card-hostname {
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.zl-card-id {
|
||||
font-size: 0.7rem;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.zl-pill {
|
||||
padding: 2px 8px;
|
||||
border-radius: 12px;
|
||||
font-size: 0.7rem;
|
||||
font-weight: bold;
|
||||
background: #222;
|
||||
}
|
||||
|
||||
.zl-pill.online {
|
||||
color: #00ffa0;
|
||||
background: rgba(0, 255, 160, 0.1);
|
||||
}
|
||||
|
||||
.zl-pill.idle {
|
||||
color: #ffcc00;
|
||||
background: rgba(255, 204, 0, 0.1);
|
||||
}
|
||||
|
||||
.zl-pill.offline {
|
||||
color: #ff3333;
|
||||
background: rgba(255, 51, 51, 0.1);
|
||||
}
|
||||
|
||||
/* ECG Animation */
|
||||
.zl-ecg-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.ecg {
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
max-width: 140px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 6px;
|
||||
border: 1px solid #111;
|
||||
}
|
||||
|
||||
.ecg-wrapper {
|
||||
display: flex;
|
||||
width: 300%;
|
||||
animation: ecg-slide linear infinite;
|
||||
}
|
||||
|
||||
.ecg svg {
|
||||
width: 33.33%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ecg path {
|
||||
fill: none;
|
||||
stroke-width: 1.5;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
.ecg.green path {
|
||||
stroke: #00ffa0;
|
||||
filter: drop-shadow(0 0 2px #00ffa0);
|
||||
}
|
||||
|
||||
.ecg.yellow path {
|
||||
stroke: #ffcc00;
|
||||
filter: drop-shadow(0 0 2px #ffcc00);
|
||||
}
|
||||
|
||||
.ecg.orange path {
|
||||
stroke: #ff8800;
|
||||
filter: drop-shadow(0 0 2px #ff8800);
|
||||
}
|
||||
|
||||
.ecg.red path {
|
||||
stroke: #ff3333;
|
||||
}
|
||||
|
||||
.ecg.flat .ecg-wrapper {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
@keyframes ecg-slide {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(-33.33%);
|
||||
}
|
||||
}
|
||||
|
||||
.zl-ecg-counter {
|
||||
font-size: 0.7rem;
|
||||
color: var(--muted);
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.zl-card-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 0.75rem;
|
||||
color: #ccc;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.zl-card-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 4px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* Console output items */
|
||||
.console-line {
|
||||
margin-bottom: 4px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.console-time {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.console-type {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.console-type.tx {
|
||||
color: var(--acid);
|
||||
}
|
||||
|
||||
.console-type.rx {
|
||||
color: #00aaff;
|
||||
}
|
||||
|
||||
.console-type.info {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.console-type.error {
|
||||
color: #ff3333;
|
||||
}
|
||||
|
||||
.console-type.success {
|
||||
color: #00ffa0;
|
||||
}
|
||||
|
||||
.console-target {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.console-content pre {
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.zl-log-line {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
/* Mobile Optimization */
|
||||
@media (max-width: 900px) {
|
||||
.zombieland-container.page-with-sidebar {
|
||||
height: auto;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.zombieland-container .zl-sidebar {
|
||||
width: 100%;
|
||||
max-height: none;
|
||||
flex-shrink: 0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.zl-stats-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.zl-toolbar {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.zl-main-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.zl-console-panel {
|
||||
height: 350px;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.zl-agents-panel {
|
||||
height: 350px;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.zl-console-input-row {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.zl-target-select,
|
||||
.zl-cmd-input {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.zl-card-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.zl-card-info {
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
}
|
||||
@@ -980,7 +980,7 @@ body.console-docked .app-container {
|
||||
.cfg-host {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
max-height: 56vh;
|
||||
max-height: min(56vh, calc(100vh - var(--h-topbar, 56px) - var(--h-bottombar, 56px) - 140px));
|
||||
overflow: auto;
|
||||
padding-right: 4px;
|
||||
}
|
||||
@@ -1137,16 +1137,59 @@ body.console-docked .app-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Config sub-tab navigation */
|
||||
.cfg-subtabs {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
padding: 4px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 12px;
|
||||
background: color-mix(in oklab, var(--c-panel-2) 60%, transparent);
|
||||
border: 1px solid var(--c-border);
|
||||
overflow-x: auto;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.cfg-subtab {
|
||||
flex: 1 1 auto;
|
||||
padding: 7px 10px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 8px;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
transition: background .15s, color .15s, border-color .15s;
|
||||
}
|
||||
|
||||
.cfg-subtab:hover {
|
||||
color: var(--ink);
|
||||
background: color-mix(in oklab, var(--c-panel) 50%, transparent);
|
||||
}
|
||||
|
||||
.cfg-subtab.active {
|
||||
color: var(--acid);
|
||||
background: var(--c-panel);
|
||||
border-color: var(--c-border-strong);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
/* Inline switch (modal lists) */
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
height: 26px;
|
||||
min-width: 46px;
|
||||
flex-shrink: 0;
|
||||
background: var(--switch-track);
|
||||
border: 1px solid var(--c-border-hi);
|
||||
border-radius: 99px;
|
||||
cursor: pointer;
|
||||
box-shadow: inset 0 0 0 1px var(--glow-mid);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.switch::after {
|
||||
@@ -1170,6 +1213,11 @@ body.console-docked .app-container {
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
/* Suppress ::after thumb when .slider span is used (settings config toggles) */
|
||||
.switch:has(.slider)::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Sheet (WiFi/BT dialogs) */
|
||||
.sheet-backdrop {
|
||||
position: fixed;
|
||||
@@ -1178,7 +1226,7 @@ body.console-docked .app-container {
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 75;
|
||||
z-index: 95;
|
||||
}
|
||||
|
||||
.sheet-backdrop.show {
|
||||
@@ -1285,6 +1333,20 @@ body.console-docked .app-container {
|
||||
min-width: 50px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.cfg-subtabs {
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
gap: 2px;
|
||||
padding: 3px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.cfg-subtab {
|
||||
flex: 0 0 auto;
|
||||
padding: 6px 8px;
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Liveview dropdown (character hover) ---- */
|
||||
@@ -1602,6 +1664,20 @@ input[type="color"].theme-input {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.theme-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 12px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px dashed var(--c-border);
|
||||
}
|
||||
|
||||
.theme-actions .btn {
|
||||
flex: 1 1 auto;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
/* ---- Toast notifications ---- */
|
||||
.toast-container {
|
||||
position: fixed;
|
||||
|
||||
493
web/css/zombieland.css
Normal file
493
web/css/zombieland.css
Normal file
@@ -0,0 +1,493 @@
|
||||
/* ==========================================================================
|
||||
ZOMBIELAND (C2 Module) CSS
|
||||
========================================================================== */
|
||||
|
||||
/* Main layout constraints */
|
||||
.zombieland-container.page-with-sidebar {
|
||||
height: calc(100vh - var(--h-topbar, 56px) - var(--h-bottombar, 56px) - 24px);
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.zl-sidebar.page-sidebar {
|
||||
width: 260px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--grad-card);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 12px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.zl-main.page-main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
/* Sidebar structure */
|
||||
.zl-stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 8px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border: 1px solid var(--c-border);
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.stat-item .stat-value {
|
||||
font-weight: bold;
|
||||
color: var(--acid);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.stat-item .stat-label {
|
||||
font-size: 0.8rem;
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.zl-toolbar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
/* Modals */
|
||||
.modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: var(--grad-card);
|
||||
border: 1px solid var(--c-border);
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
/* Main Grid Layout */
|
||||
.zl-main-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
|
||||
gap: 12px;
|
||||
flex: 1;
|
||||
/* Takes available space except logs */
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.zl-console-panel,
|
||||
.zl-agents-panel,
|
||||
.zl-logs-panel {
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 12px;
|
||||
background: var(--c-panel);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Log Panel underneath */
|
||||
.zl-logs-panel {
|
||||
height: 150px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.zl-panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-bottom: 1px solid var(--c-border);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.zl-panel-title {
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
color: var(--acid);
|
||||
}
|
||||
|
||||
.zl-quickbar {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.quick-cmd {
|
||||
background: transparent;
|
||||
border: 1px solid var(--c-border-strong);
|
||||
color: var(--muted);
|
||||
font-size: 0.7rem;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.quick-cmd:hover {
|
||||
color: var(--acid);
|
||||
border-color: var(--acid);
|
||||
}
|
||||
|
||||
.zl-console-output,
|
||||
.zl-logs-output {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
font-family: 'Fira Code', monospace;
|
||||
font-size: 0.8rem;
|
||||
background: #020406;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* Controls */
|
||||
.zl-console-input-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
border-top: 1px solid var(--c-border);
|
||||
background: var(--c-panel-2);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.zl-target-select,
|
||||
.zl-cmd-input,
|
||||
.zl-search-input {
|
||||
background: #000;
|
||||
color: #fff;
|
||||
border: 1px solid var(--c-border-strong);
|
||||
padding: 6px 10px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.zl-cmd-input {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.zl-toolbar-left {
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
max-width: 200px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.zl-search-input {
|
||||
width: 100%;
|
||||
border-radius: 6px;
|
||||
padding: 4px 20px 4px 8px;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.zl-search-clear {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
color: var(--muted);
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.zl-agents-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* Agent Card Styles */
|
||||
.zl-agent-card {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 8px;
|
||||
padding: 8px 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
transition: 0.2s ease-out;
|
||||
}
|
||||
|
||||
.zl-agent-card.selected {
|
||||
border-color: var(--acid);
|
||||
background: rgba(0, 255, 160, 0.05);
|
||||
}
|
||||
|
||||
.zl-agent-card:hover {
|
||||
border-color: var(--c-border-hi);
|
||||
}
|
||||
|
||||
.zl-card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.zl-card-identity {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.zl-card-hostname {
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.zl-card-id {
|
||||
font-size: 0.7rem;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.zl-pill {
|
||||
padding: 2px 8px;
|
||||
border-radius: 12px;
|
||||
font-size: 0.7rem;
|
||||
font-weight: bold;
|
||||
background: #222;
|
||||
}
|
||||
|
||||
.zl-pill.online {
|
||||
color: #00ffa0;
|
||||
background: rgba(0, 255, 160, 0.1);
|
||||
}
|
||||
|
||||
.zl-pill.idle {
|
||||
color: #ffcc00;
|
||||
background: rgba(255, 204, 0, 0.1);
|
||||
}
|
||||
|
||||
.zl-pill.offline {
|
||||
color: #ff3333;
|
||||
background: rgba(255, 51, 51, 0.1);
|
||||
}
|
||||
|
||||
/* ECG Animation */
|
||||
.zl-ecg-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.ecg {
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
max-width: 140px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 6px;
|
||||
border: 1px solid #111;
|
||||
}
|
||||
|
||||
.ecg-wrapper {
|
||||
display: flex;
|
||||
width: 300%;
|
||||
animation: ecg-slide linear infinite;
|
||||
}
|
||||
|
||||
.ecg svg {
|
||||
width: 33.33%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ecg path {
|
||||
fill: none;
|
||||
stroke-width: 1.5;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
.ecg.green path {
|
||||
stroke: #00ffa0;
|
||||
filter: drop-shadow(0 0 2px #00ffa0);
|
||||
}
|
||||
|
||||
.ecg.yellow path {
|
||||
stroke: #ffcc00;
|
||||
filter: drop-shadow(0 0 2px #ffcc00);
|
||||
}
|
||||
|
||||
.ecg.orange path {
|
||||
stroke: #ff8800;
|
||||
filter: drop-shadow(0 0 2px #ff8800);
|
||||
}
|
||||
|
||||
.ecg.red path {
|
||||
stroke: #ff3333;
|
||||
}
|
||||
|
||||
.ecg.flat .ecg-wrapper {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
@keyframes ecg-slide {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(-33.33%);
|
||||
}
|
||||
}
|
||||
|
||||
.zl-ecg-counter {
|
||||
font-size: 0.7rem;
|
||||
color: var(--muted);
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.zl-card-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 0.75rem;
|
||||
color: #ccc;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.zl-card-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 4px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* Console output items */
|
||||
.console-line {
|
||||
margin-bottom: 4px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.console-time {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.console-type {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.console-type.tx {
|
||||
color: var(--acid);
|
||||
}
|
||||
|
||||
.console-type.rx {
|
||||
color: #00aaff;
|
||||
}
|
||||
|
||||
.console-type.info {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.console-type.error {
|
||||
color: #ff3333;
|
||||
}
|
||||
|
||||
.console-type.success {
|
||||
color: #00ffa0;
|
||||
}
|
||||
|
||||
.console-target {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.console-content pre {
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.zl-log-line {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
/* Mobile Optimization */
|
||||
@media (max-width: 900px) {
|
||||
.zombieland-container.page-with-sidebar {
|
||||
height: auto;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.zombieland-container .zl-sidebar {
|
||||
width: 100%;
|
||||
max-height: none;
|
||||
flex-shrink: 0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.zl-stats-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.zl-toolbar {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.zl-main-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.zl-console-panel {
|
||||
height: 350px;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.zl-agents-panel {
|
||||
height: 350px;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.zl-console-input-row {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.zl-target-select,
|
||||
.zl-cmd-input {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.zl-card-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.zl-card-info {
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user