// Tokyo Night palette
:root {
--tn-bg: #1a1b26;
--tn-bg-dark: #16161e;
--tn-bg-card: #1f2335;
--tn-border: #292e42;
--tn-fg: #c0caf5;
--tn-fg-dim: #a9b1d6;
--tn-muted: #565f89;
--tn-blue: #7aa2f7;
--tn-cyan: #7dcfff;
--tn-purple: #bb9af7;
--tn-green: #9ece6a;
--tn-yellow: #e0af68;
--tn-red: #f7768e;
}
// Bootstrap muted override
.text-muted { color: var(--tn-fg-dim) !important; }
// Force line breaks for long unbreakable strings (filenames, paths)
h1, h2, h3, h4, h5, h6,
.filename a,
.filepath,
.stream-title,
td,
.file a,
.modal-body strong {
word-break: break-word;
overflow-wrap: anywhere;
}
// Base
* { box-sizing: border-box; }
body {
font-family: 'JetBrains Mono', monospace;
background-color: var(--tn-bg);
color: var(--tn-fg);
font-size: 1rem;
}
a {
text-decoration: none;
color: var(--tn-blue);
&:hover { color: var(--tn-cyan); }
}
// Headings
h1, h2, h3, h4, h5, h6 {
color: var(--tn-blue);
letter-spacing: 0.04em;
font-weight: 400;
}
// Cards
.card {
background-color: var(--tn-bg-card);
border: 1px solid var(--tn-border);
border-radius: 8px;
transition: border-color 0.2s, box-shadow 0.2s;
.card-header {
background-color: var(--tn-bg-dark);
border-bottom: 1px solid var(--tn-border);
color: var(--tn-blue);
letter-spacing: 0.04em;
}
.card-body { color: var(--tn-fg); }
}
// Tables
.table {
color: var(--tn-fg);
border-color: var(--tn-border);
thead th {
color: var(--tn-blue);
font-weight: 400;
border-color: var(--tn-border);
letter-spacing: 0.04em;
background-color: var(--tn-bg-dark);
}
td {
color: var(--tn-fg);
border-color: var(--tn-border);
padding: 6px 10px;
}
&.table-striped > tbody > tr:nth-of-type(odd) > * {
background-color: rgba(41, 46, 66, 0.4);
color: var(--tn-fg);
}
&.table-hover > tbody > tr:hover > * {
background-color: rgba(122, 162, 247, 0.08);
color: var(--tn-fg);
}
}
// DataTables overrides
.dataTables_wrapper {
color: var(--tn-fg);
.dataTables_filter input,
.dataTables_length select {
background-color: var(--tn-bg-dark);
border: 1px solid var(--tn-border);
color: var(--tn-fg);
border-radius: 4px;
padding: 2px 8px;
font-family: 'JetBrains Mono', monospace;
outline: none;
&:focus { border-color: var(--tn-blue); }
}
.dataTables_info,
.dataTables_filter label,
.dataTables_length label { color: var(--tn-muted); }
.dataTables_paginate .paginate_button {
color: var(--tn-muted) !important;
border-radius: 4px !important;
&:hover { background: var(--tn-bg-card) !important; color: var(--tn-blue) !important; border-color: var(--tn-border) !important; }
&.current { background: var(--tn-bg-card) !important; color: var(--tn-blue) !important; border-color: var(--tn-border) !important; }
&.disabled { color: var(--tn-border) !important; }
}
}
// Buttons
.btn {
font-family: 'JetBrains Mono', monospace;
border-radius: 4px;
letter-spacing: 0.02em;
&.border-spinner { margin-right: 2px; position: relative; top: 1px; }
&.inprogress { display: inline-flex; gap: 6px; align-items: center; }
}
.btn-primary {
background-color: var(--tn-blue);
border-color: var(--tn-blue);
color: var(--tn-bg-dark);
&:hover { background-color: var(--tn-cyan); border-color: var(--tn-cyan); color: var(--tn-bg-dark); }
}
.btn-warning {
background-color: var(--tn-yellow);
border-color: var(--tn-yellow);
color: var(--tn-bg-dark);
&:hover { background-color: #f0c070; border-color: #f0c070; color: var(--tn-bg-dark); }
}
.btn-success {
background-color: var(--tn-green);
border-color: var(--tn-green);
color: var(--tn-bg-dark);
&:hover { background-color: #acd87a; border-color: #acd87a; color: var(--tn-bg-dark); }
}
.btn-danger {
background-color: var(--tn-red);
border-color: var(--tn-red);
color: var(--tn-bg-dark);
&:hover { background-color: #f98a9e; border-color: #f98a9e; color: var(--tn-bg-dark); }
}
.btn-outline-secondary {
border-color: var(--tn-border);
color: var(--tn-fg-dim);
background-color: transparent;
&:hover { background-color: var(--tn-bg-card); border-color: var(--tn-blue); color: var(--tn-blue); box-shadow: 0 0 12px rgba(122,162,247,0.15); }
}
.btn-outline-primary {
border-color: var(--tn-blue);
color: var(--tn-blue);
background-color: transparent;
&:hover { background-color: rgba(122,162,247,0.1); color: var(--tn-blue); }
}
.btn-close {
filter: invert(1) brightness(0.6);
&:hover { filter: invert(1) brightness(1); }
}
// Forms
.form-select, .form-control {
background-color: var(--tn-bg-dark);
border: 1px solid var(--tn-border);
color: var(--tn-fg);
font-family: 'JetBrains Mono', monospace;
border-radius: 4px;
&:focus {
background-color: var(--tn-bg-dark);
border-color: var(--tn-blue);
color: var(--tn-fg);
box-shadow: 0 0 0 2px rgba(122,162,247,0.15);
}
option { background-color: var(--tn-bg-card); }
}
.form-check-input {
background-color: var(--tn-bg-dark);
border-color: var(--tn-border);
&:checked { background-color: var(--tn-blue); border-color: var(--tn-blue); }
&:focus { box-shadow: 0 0 0 2px rgba(122,162,247,0.15); border-color: var(--tn-blue); }
}
.form-check-label { color: var(--tn-fg-dim); }
.input-group-text {
background-color: var(--tn-bg-dark);
border-color: var(--tn-border);
color: var(--tn-muted);
font-family: 'JetBrains Mono', monospace;
}
// Alerts
.alert {
background-color: var(--tn-bg-card);
border-color: var(--tn-border);
color: var(--tn-fg);
&.alert-dark {
background-color: var(--tn-bg-dark);
border-color: var(--tn-border);
color: var(--tn-fg-dim);
}
}
// Badges
.badge {
font-family: 'JetBrains Mono', monospace;
font-weight: 400;
&.bg-success { background-color: var(--tn-green) !important; color: var(--tn-bg-dark); }
&.bg-danger { background-color: var(--tn-red) !important; color: var(--tn-bg-dark); }
&.bg-warning { background-color: var(--tn-yellow) !important; color: var(--tn-bg-dark); }
&.bg-secondary { background-color: var(--tn-muted) !important; color: var(--tn-fg); }
&.bg-light { background-color: var(--tn-bg-dark) !important; color: var(--tn-fg) !important; border-color: var(--tn-border) !important; }
}
// Modal
.modal-content {
background-color: var(--tn-bg-card);
border: 1px solid var(--tn-border);
border-radius: 8px;
color: var(--tn-fg);
}
.modal-header {
background-color: var(--tn-bg-dark);
border-bottom: 1px solid var(--tn-border);
color: var(--tn-blue);
}
.modal-footer {
background-color: var(--tn-bg-dark);
border-top: 1px solid var(--tn-border);
color: var(--tn-muted);
}
// List group
.list-group-item {
background-color: var(--tn-bg-card);
border-color: var(--tn-border);
color: var(--tn-fg);
&.task {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
gap: 12px;
.file {
display: flex;
flex-direction: row;
gap: 8px;
align-items: center;
min-width: 0;
a { min-width: 0; }
}
}
}
// Progress bar
.progress {
background-color: var(--tn-bg-dark);
border: 1px solid var(--tn-border);
.progress-bar {
background-color: var(--tn-blue);
}
}
// Spinners
.loader {
width: 48px;
height: 48px;
border: 5px solid var(--tn-border);
border-bottom-color: var(--tn-blue);
border-radius: 50%;
display: inline-block;
box-sizing: border-box;
animation: rotation 1s linear infinite;
}
@keyframes rotation {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-spinner-container {
width: 100%;
margin: 50px auto;
text-align: center;
}
.sm-spinner { width: 18px; height: 18px; border-width: 3px; }
// Nav brand
.nav-brand {
display: flex;
align-items: center;
line-height: 1;
}
.nav-icon-btn {
background-color: var(--tn-bg-card);
border: 1px solid var(--tn-border);
color: var(--tn-muted);
border-radius: 50% !important;
width: 52px;
height: 52px;
display: flex;
align-items: center;
justify-content: center;
transition: border-color 0.2s, box-shadow 0.2s, color 0.2s;
&:hover {
border-color: var(--tn-blue);
color: var(--tn-blue);
box-shadow: 0 0 12px rgba(122,162,247,0.25);
}
}
// Header nav button
.open-transcoding-tasks {
background-color: var(--tn-bg-card);
border: 1px solid var(--tn-border);
color: var(--tn-muted);
border-radius: 50% !important;
width: 52px;
height: 52px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
transition: border-color 0.2s, box-shadow 0.2s, color 0.2s;
&:hover {
border-color: var(--tn-blue);
color: var(--tn-blue);
box-shadow: 0 0 12px rgba(122,162,247,0.25);
}
.total-tasks:not(:empty) {
position: absolute;
top: -6px;
right: -6px;
background-color: var(--tn-yellow);
color: var(--tn-bg-dark);
font-size: 0.75rem;
font-weight: 700;
min-width: 20px;
height: 20px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
padding: 0 5px;
line-height: 1;
}
}
// Transcoding form
.transcodate-form-container {
margin-top: 20px;
display: flex;
flex-wrap: wrap;
flex-direction: row;
gap: 10px;
> .form-control {
display: flex;
flex-wrap: nowrap;
flex-direction: row;
justify-content: flex-start;
gap: 10px;
align-items: center;
background: transparent;
border: none;
padding: 0;
> strong {
white-space: nowrap;
display: inline-block;
width: 110px;
color: var(--tn-muted);
font-weight: 400;
font-size: 0.875rem;
letter-spacing: 0.02em;
}
}
.arrow-to { color: var(--tn-muted); }
.btns { width: 100%; }
}
.crf-range { margin-left: 5px; color: var(--tn-muted); }
#progress {
margin-top: 20px;
margin-bottom: 0;
font-size: 0.85rem;
color: var(--tn-fg-dim);
}
// Modal empty state
.empty-tasks-message { color: var(--tn-fg-dim); }
// Media list file details
.filename a {
color: var(--tn-fg);
font-weight: 400;
&:hover { color: var(--tn-blue); }
}
.filepath {
font-size: 0.78rem;
color: var(--tn-muted);
margin-bottom: 6px;
}
.filedetails {
display: flex;
flex-direction: column;
gap: 3px;
}
.streams-section {
display: flex;
align-items: flex-start;
gap: 8px;
}
.stream-label {
font-size: 0.7rem;
color: var(--tn-muted);
letter-spacing: 0.06em;
text-transform: uppercase;
min-width: 36px;
padding-top: 3px;
flex-shrink: 0;
}
.stream-rows {
display: flex;
flex-direction: column;
gap: 3px;
}
.stream-row {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 4px;
}
.stream-bitrate {
font-size: 0.75rem;
color: var(--tn-muted);
}
.stream-title {
font-size: 0.75rem;
color: var(--tn-fg-dim);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 380px;
}
// Language badges
.lang-badge {
font-size: 0.68rem;
letter-spacing: 0.04em;
text-transform: uppercase;
min-width: 30px;
text-align: center;
}
.lang-ukr { background-color: var(--tn-cyan) !important; color: var(--tn-bg-dark); }
.lang-eng { background-color: var(--tn-blue) !important; color: var(--tn-bg-dark); }
.lang-rus { background-color: var(--tn-red) !important; color: var(--tn-bg-dark); }
.lang-jpn { background-color: var(--tn-purple) !important; color: var(--tn-bg-dark); }
.lang-deu,
.lang-fra,
.lang-spa,
.lang-ita,
.lang-pol { background-color: var(--tn-green) !important; color: var(--tn-bg-dark); }
.lang-und { background-color: var(--tn-muted) !important; color: var(--tn-fg); }
// Footer stats
.footer {
border-top: 1px solid var(--tn-border);
padding: 16px 0 20px;
}
.footer-stats {
display: flex;
align-items: center;
gap: 20px;
flex-wrap: wrap;
}
.footer-stat {
display: flex;
align-items: center;
gap: 6px;
}
.footer-stat-icon {
color: var(--tn-muted);
font-size: 0.95rem;
}
.footer-stat-value {
color: var(--tn-blue);
font-size: 0.9rem;
letter-spacing: 0.02em;
}
.footer-stat-label {
color: var(--tn-muted);
font-size: 0.78rem;
letter-spacing: 0.03em;
}
.footer-stat-divider {
width: 1px;
height: 16px;
background-color: var(--tn-border);
}
// Nav logo
.nav-logo {
height: 32px;
width: auto;
display: block;
transition: opacity 0.2s, filter 0.2s;
filter: brightness(0.85);
.nav-brand:hover & {
opacity: 1;
filter: brightness(1) drop-shadow(0 0 8px rgba(122, 162, 247, 0.5));
}
}
// Auth logo
.auth-logo {
max-height: 100px;
width: auto;
display: block;
margin: 0 auto;
}
// Nav user info
.nav-user-divider {
width: 1px;
height: 24px;
background-color: var(--tn-border);
margin: 0 4px;
flex-shrink: 0;
}
.nav-username {
color: var(--tn-muted);
font-size: 0.78rem;
letter-spacing: 0.04em;
white-space: nowrap;
line-height: 1;
}
// Auth pages
.auth-page {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem 1rem;
}
.auth-card {
background-color: var(--tn-bg-card);
border: 1px solid var(--tn-border);
border-radius: 10px;
padding: 2.5rem 2rem;
width: 100%;
max-width: 380px;
}
.auth-logo-space {
height: 100px;
margin-bottom: 1.5rem;
display: flex;
align-items: center;
justify-content: center;
}
.auth-title {
color: var(--tn-blue);
font-size: 1.15rem;
letter-spacing: 0.06em;
font-weight: 400;
margin-bottom: 0.25rem;
text-align: center;
}
.auth-subtitle {
color: var(--tn-muted);
font-size: 0.78rem;
text-align: center;
margin-bottom: 1.5rem;
letter-spacing: 0.03em;
}
.auth-field {
margin-bottom: 1.1rem;
label {
display: block;
color: var(--tn-muted);
font-size: 0.78rem;
letter-spacing: 0.04em;
margin-bottom: 0.3rem;
}
}
.auth-input-wrap {
position: relative;
display: flex;
align-items: center;
}
.auth-input {
width: 100%;
background-color: var(--tn-bg-dark);
border: 1px solid var(--tn-border);
border-radius: 6px;
color: var(--tn-fg);
font-family: 'JetBrains Mono', monospace;
font-size: 0.9rem;
padding: 0.55rem 2.4rem 0.55rem 0.75rem;
outline: none;
transition: border-color 0.2s;
&:focus {
border-color: var(--tn-blue);
}
// standalone input (no wrap)
&:not(.auth-input-wrap .auth-input) {
padding-right: 0.75rem;
}
}
.auth-eye-btn {
position: absolute;
right: 0.55rem;
background: none;
border: none;
color: var(--tn-muted);
cursor: pointer;
padding: 0;
line-height: 1;
font-size: 1rem;
&:hover { color: var(--tn-fg-dim); }
}
.auth-btn {
width: 100%;
margin-top: 0.5rem;
padding: 0.6rem;
background-color: var(--tn-blue);
color: var(--tn-bg-dark);
border: none;
border-radius: 6px;
font-family: 'JetBrains Mono', monospace;
font-size: 0.9rem;
letter-spacing: 0.04em;
cursor: pointer;
transition: background-color 0.2s;
&:hover { background-color: var(--tn-cyan); }
&:disabled { opacity: 0.5; cursor: default; }
}
.auth-error {
background-color: rgba(247, 118, 142, 0.12);
border: 1px solid var(--tn-red);
border-radius: 6px;
color: var(--tn-red);
font-size: 0.82rem;
padding: 0.5rem 0.75rem;
margin-bottom: 1rem;
}
.auth-success {
background-color: rgba(158, 206, 106, 0.12);
border: 1px solid var(--tn-green);
border-radius: 6px;
color: var(--tn-green);
font-size: 0.82rem;
padding: 0.5rem 0.75rem;
margin-bottom: 1rem;
}
// Scanning message
.scaning-process-container {
font-size: 0.85rem;
color: var(--tn-muted);
background-color: var(--tn-bg-dark);
border-color: var(--tn-border);
word-break: break-all;
overflow-wrap: anywhere;
}
// ── Notification bell badge ────────────────────────────────────────────────────
.open-notifications {
position: relative;
.notif-badge:not(:empty) {
position: absolute;
top: -6px;
right: -6px;
background-color: var(--tn-red);
color: var(--tn-bg-dark);
font-size: 0.7rem;
font-weight: 700;
min-width: 18px;
height: 18px;
border-radius: 9px;
display: flex;
align-items: center;
justify-content: center;
padding: 0 4px;
line-height: 1;
}
}
// ── Notification toast ─────────────────────────────────────────────────────────
.notif-toast {
background-color: var(--tn-bg-card);
border: 1px solid var(--tn-border);
border-left: 3px solid var(--notif-color, var(--tn-blue));
border-radius: 6px;
padding: 10px 12px;
margin-bottom: 8px;
opacity: 0;
transform: translateX(16px);
transition: opacity 0.25s, transform 0.25s;
max-width: 360px;
font-size: 0.83rem;
&.show {
opacity: 1;
transform: translateX(0);
}
.notif-toast-header {
display: flex;
align-items: center;
gap: 7px;
}
.notif-toast-icon {
color: var(--notif-color, var(--tn-blue));
flex-shrink: 0;
font-size: 0.9rem;
}
.notif-toast-title {
color: var(--tn-fg);
font-weight: 400;
letter-spacing: 0.02em;
flex-grow: 1;
}
.notif-toast-msg {
margin-top: 6px;
color: var(--tn-muted);
font-size: 0.78rem;
max-height: 80px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
word-break: break-all;
overflow-wrap: anywhere;
}
}
// ── Transcoding tasks offcanvas ────────────────────────────────────────────────
.transcoding-offcanvas {
background-color: var(--tn-bg-card);
border-left: 1px solid var(--tn-border);
width: 480px !important;
font-family: 'JetBrains Mono', monospace;
.offcanvas-header {
background-color: var(--tn-bg-dark);
border-bottom: 1px solid var(--tn-border);
padding: 16px 20px;
.offcanvas-title {
color: var(--tn-blue);
font-size: 0.95rem;
letter-spacing: 0.04em;
font-weight: 400;
}
}
.transcoding-toolbar {
border-bottom: 1px solid var(--tn-border);
background-color: var(--tn-bg-dark);
flex-shrink: 0;
min-height: 40px;
}
.transcoding-toolbar-count {
color: var(--tn-muted);
font-size: 0.8rem;
letter-spacing: 0.03em;
.total-tasks { color: var(--tn-yellow); }
}
.transcoding-tasks-container {
.list-group-item.task {
background-color: transparent;
border-color: rgba(41, 46, 66, 0.6);
padding: 14px 20px;
}
}
}
// ── Notification offcanvas ─────────────────────────────────────────────────────
.notifications-offcanvas {
background-color: var(--tn-bg-card);
border-left: 1px solid var(--tn-border);
width: 480px !important;
font-family: 'JetBrains Mono', monospace;
.offcanvas-header {
background-color: var(--tn-bg-dark);
border-bottom: 1px solid var(--tn-border);
padding: 16px 20px;
.offcanvas-title {
color: var(--tn-blue);
font-size: 0.95rem;
letter-spacing: 0.04em;
font-weight: 400;
}
}
.notif-toolbar {
border-bottom: 1px solid var(--tn-border);
background-color: var(--tn-bg-dark);
flex-shrink: 0;
padding: 8px 16px;
.btn {
font-size: 0.8rem;
padding: 4px 12px;
}
}
}
.notif-list {
padding: 8px 0;
}
.notif-item {
padding: 14px 20px;
border-bottom: 1px solid rgba(41, 46, 66, 0.5);
transition: background-color 0.15s, opacity 0.25s;
border-left: 3px solid transparent;
&.is-unread {
border-left-color: var(--notif-color, var(--tn-blue));
background-color: rgba(122, 162, 247, 0.04);
}
&.removing { opacity: 0; }
&:hover { background-color: rgba(122, 162, 247, 0.05); }
.notif-item-header {
display: flex;
align-items: flex-start;
gap: 10px;
}
.notif-item-icon {
color: var(--notif-color, var(--tn-blue));
font-size: 1rem;
flex-shrink: 0;
margin-top: 2px;
}
.notif-item-meta {
flex-grow: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 3px;
}
.notif-item-title {
color: var(--tn-fg);
font-size: 0.95rem;
letter-spacing: 0.02em;
word-break: break-word;
}
.notif-item-time {
color: var(--tn-muted);
font-size: 0.8rem;
}
.notif-delete-btn {
background: none;
border: none;
color: var(--tn-muted);
padding: 0 2px;
line-height: 1;
cursor: pointer;
flex-shrink: 0;
font-size: 1.1rem;
opacity: 0;
transition: color 0.15s, opacity 0.15s;
&:hover { color: var(--tn-red); }
}
&:hover .notif-delete-btn { opacity: 1; }
.notif-item-msg {
margin-top: 8px;
color: var(--tn-muted);
font-size: 0.86rem;
word-break: break-all;
overflow-wrap: anywhere;
line-height: 1.55;
}
.notif-expand-btn {
background: none;
border: none;
color: var(--tn-blue);
font-family: 'JetBrains Mono', monospace;
font-size: 0.76rem;
cursor: pointer;
padding: 3px 0;
margin-top: 3px;
&:hover { color: var(--tn-cyan); }
}
}