pre-img swap

This commit is contained in:
Matt Batchelder
2026-03-23 21:09:27 -04:00
parent 87474b05a9
commit bbe8c1860c
395 changed files with 29643 additions and 712 deletions

View File

@@ -3,6 +3,8 @@
February 4, 2026
============================================================================= */
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&display=swap');
:root {
color-scheme: dark;
@@ -14,9 +16,10 @@
--ots-border-soft: #243047;
--ots-text: #e6eefb;
--ots-text-muted: #a9b6cc;
--ots-text-faint: #7f8aa3;
--ots-primary: #4f8cff;
--ots-primary-2: #2f6bff;
--ots-text-faint: #8d99b4;
--ots-primary: #e87800;
--ots-primary-rgb: 232, 120, 0;
--ots-primary-2: #c46500;
--ots-success: #2ad4a4;
--ots-warning: #f4b860;
--ots-danger: #ff6b6b;
@@ -26,9 +29,9 @@
--ots-shadow-md: 0 8px 18px rgba(0, 0, 0, 0.25);
--ots-shadow-sm: 0 3px 8px rgba(0, 0, 0, 0.2);
--ots-radius-sm: 6px;
--ots-radius-md: 10px;
--ots-radius-lg: 14px;
--ots-radius-sm: 4px;
--ots-radius-md: 8px;
--ots-radius-lg: 12px;
--ots-transition: 160ms ease;
@@ -37,7 +40,7 @@
--modal-backdrop-blur: 6px;
--modal-bg: #141c2b;
--modal-border: #2c3a54;
--modal-radius: 16px;
--modal-radius: 12px;
--modal-shadow: 0 24px 64px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(255, 255, 255, 0.04);
--modal-header-bg: #0f172a;
--modal-header-border: #2c3a54;
@@ -51,8 +54,8 @@
--modal-input-bg: #0b111a;
--modal-input-border: #2c3a54;
--modal-input-text: #e6eefb;
--modal-input-focus-border: #4f8cff;
--modal-input-focus-ring: rgba(79, 140, 255, 0.2);
--modal-input-focus-border: #e87800;
--modal-input-focus-ring: rgba(var(--ots-primary-rgb), 0.2);
}
/* =============================================================================
@@ -66,9 +69,10 @@ body {
}
body {
font-family: "Inter", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
font-family: "DM Sans", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
font-feature-settings: "kern" 1, "liga" 1;
}
a,
@@ -104,6 +108,38 @@ hr {
border-color: var(--ots-border);
}
/* ---------- Accessibility: focus-visible ---------- */
*:focus-visible {
outline: 2px solid var(--ots-primary);
outline-offset: 2px;
}
.btn:focus-visible,
.form-control:focus-visible,
.form-select:focus-visible,
.nav-link:focus-visible {
outline: 2px solid var(--ots-primary);
outline-offset: 2px;
box-shadow: 0 0 0 3px rgba(var(--ots-primary-rgb), 0.25);
}
.ots-sidebar li a:focus-visible {
outline: 2px solid var(--ots-primary);
outline-offset: -2px;
border-radius: var(--ots-radius-sm);
}
.sidebar-group-toggle:focus-visible {
outline: 2px solid var(--ots-primary);
outline-offset: -2px;
border-radius: var(--ots-radius-sm);
}
table tbody tr:focus-within {
outline: 1px solid var(--ots-primary);
outline-offset: -1px;
}
/* =============================================================================
LAYOUT WRAPPERS
============================================================================= */
@@ -211,7 +247,7 @@ hr {
.ots-topbar .nav-link:hover,
.ots-topbar .nav-item.open .nav-link,
.ots-topbar .nav-item.active .nav-link {
background: rgba(79, 140, 255, 0.18);
background: rgba(var(--ots-primary-rgb), 0.18);
color: var(--ots-primary);
}
@@ -274,9 +310,9 @@ hr {
display: flex;
align-items: center;
justify-content: center;
background: rgba(79, 140, 255, 0.15);
border: 1px solid rgba(79, 140, 255, 0.3);
border-radius: 6px;
background: rgba(var(--ots-primary-rgb), 0.15);
border: 1px solid rgba(var(--ots-primary-rgb), 0.3);
border-radius: var(--ots-radius-sm);
font-size: 18px;
color: var(--ots-primary);
flex-shrink: 0;
@@ -354,7 +390,7 @@ hr {
gap: 12px;
margin: 0 8px;
padding: 10px 12px;
border-radius: 6px;
border-radius: var(--ots-radius-sm);
color: var(--ots-text);
text-decoration: none;
transition: background var(--ots-transition), color var(--ots-transition);
@@ -363,12 +399,12 @@ hr {
}
.ots-sidebar li.sidebar-main > a:hover {
background: rgba(79, 140, 255, 0.12);
background: rgba(var(--ots-primary-rgb), 0.12);
color: var(--ots-primary);
}
.ots-sidebar li.sidebar-main > a.active {
background: rgba(79, 140, 255, 0.2);
background: rgba(var(--ots-primary-rgb), 0.2);
color: var(--ots-primary);
}
@@ -379,7 +415,7 @@ hr {
gap: 12px;
margin: 0 8px;
padding: 10px 12px;
border-radius: 6px;
border-radius: var(--ots-radius-sm);
color: var(--ots-text);
text-decoration: none;
transition: background var(--ots-transition), color var(--ots-transition);
@@ -393,12 +429,12 @@ hr {
}
.ots-sidebar li.sidebar-section > a.sidebar-section-toggle:hover {
background: rgba(79, 140, 255, 0.12);
background: rgba(var(--ots-primary-rgb), 0.12);
color: var(--ots-primary);
}
.ots-sidebar li.sidebar-section > a.sidebar-section-toggle.active {
background: rgba(79, 140, 255, 0.12);
background: rgba(var(--ots-primary-rgb), 0.12);
color: var(--ots-primary);
}
@@ -418,7 +454,7 @@ hr {
margin: 0;
padding: 4px 0;
display: none;
background: rgba(79, 140, 255, 0.05);
background: rgba(var(--ots-primary-rgb), 0.05);
}
.ots-sidebar .sidebar-subsection.active {
@@ -445,12 +481,12 @@ hr {
}
.ots-sidebar li.sidebar-list > a:hover {
background: rgba(79, 140, 255, 0.12);
background: rgba(var(--ots-primary-rgb), 0.12);
color: var(--ots-primary);
}
.ots-sidebar li.sidebar-list > a.active {
background: rgba(79, 140, 255, 0.15);
background: rgba(var(--ots-primary-rgb), 0.15);
color: var(--ots-primary);
}
@@ -562,13 +598,13 @@ html::before, html::after, body::before, body::after, #page-wrapper::before, #pa
}
.ots-user-profile-link:hover {
background: rgba(79, 140, 255, 0.12);
background: rgba(var(--ots-primary-rgb), 0.12);
color: var(--ots-primary);
}
#sidebar-wrapper .sidebar-main a:hover,
#sidebar-wrapper .sidebar-list a:hover {
background: rgba(79, 140, 255, 0.12);
background: rgba(var(--ots-primary-rgb), 0.12);
color: var(--ots-primary);
}
@@ -699,7 +735,7 @@ input[type="password"]:focus,
select:focus,
textarea:focus {
border-color: var(--ots-primary);
box-shadow: 0 0 0 2px rgba(79, 140, 255, 0.2);
box-shadow: 0 0 0 2px rgba(var(--ots-primary-rgb), 0.2);
outline: none;
}
@@ -721,11 +757,11 @@ textarea:focus {
}
.table-striped > tbody > tr:nth-of-type(odd) {
background: rgba(79, 140, 255, 0.04);
background: rgba(var(--ots-primary-rgb), 0.04);
}
.table-hover > tbody > tr:hover {
background: rgba(79, 140, 255, 0.08);
background: rgba(var(--ots-primary-rgb), 0.08);
}
.dataTables_wrapper .dataTables_length,
@@ -763,7 +799,7 @@ textarea:focus {
.dropdown-item:hover,
.dropdown-menu > li > a:hover {
background: rgba(79, 140, 255, 0.12);
background: rgba(var(--ots-primary-rgb), 0.12);
color: var(--ots-primary);
}
@@ -920,7 +956,7 @@ textarea:focus {
.modal-footer .btn:hover,
.modal-footer button:hover {
background: rgba(79, 140, 255, 0.08) !important;
background: rgba(var(--ots-primary-rgb), 0.08) !important;
color: var(--ots-primary) !important;
border-color: var(--ots-primary) !important;
}
@@ -966,7 +1002,7 @@ textarea:focus {
.modal-body textarea:focus,
.modal-body select:focus {
border-color: var(--modal-input-focus-border, var(--ots-primary)) !important;
box-shadow: 0 0 0 3px var(--modal-input-focus-ring, rgba(79, 140, 255, 0.2)) !important;
box-shadow: 0 0 0 3px var(--modal-input-focus-ring, rgba(var(--ots-primary-rgb), 0.2)) !important;
outline: none !important;
}
@@ -991,7 +1027,7 @@ textarea:focus {
.modal-body .tagsinput:focus-within,
.modal-body .tokenfield:focus-within {
border-color: var(--modal-input-focus-border, var(--ots-primary)) !important;
box-shadow: 0 0 0 3px var(--modal-input-focus-ring, rgba(79, 140, 255, 0.2)) !important;
box-shadow: 0 0 0 3px var(--modal-input-focus-ring, rgba(var(--ots-primary-rgb), 0.2)) !important;
}
.modal-body .bootstrap-tagsinput input,
@@ -1016,9 +1052,9 @@ textarea:focus {
.modal-body .bootstrap-tagsinput .badge,
.modal-body .tagsinput .tag,
.modal-body .tokenfield .token {
background: rgba(79, 140, 255, 0.18) !important;
border: 1px solid rgba(79, 140, 255, 0.35) !important;
color: var(--ots-primary, #4f8cff) !important;
background: rgba(var(--ots-primary-rgb), 0.18) !important;
border: 1px solid rgba(var(--ots-primary-rgb), 0.35) !important;
color: var(--ots-primary, #e87800) !important;
border-radius: 999px !important;
padding: 2px 8px !important;
font-size: 0.8rem;
@@ -1028,7 +1064,7 @@ textarea:focus {
.modal-body .bootstrap-tagsinput .tag [data-role="remove"],
.modal-body .bootstrap-tagsinput .badge [data-role="remove"],
.modal-body .tokenfield .token .close {
color: var(--ots-primary, #4f8cff) !important;
color: var(--ots-primary, #e87800) !important;
opacity: 0.7;
margin-left: 4px;
cursor: pointer;
@@ -1062,9 +1098,9 @@ textarea:focus {
.bootstrap-tagsinput .badge,
.tagsinput .tag,
.tokenfield .token {
background: rgba(79, 140, 255, 0.18) !important;
border: 1px solid rgba(79, 140, 255, 0.35) !important;
color: var(--ots-primary, #4f8cff) !important;
background: rgba(var(--ots-primary-rgb), 0.18) !important;
border: 1px solid rgba(var(--ots-primary-rgb), 0.35) !important;
color: var(--ots-primary, #e87800) !important;
border-radius: 999px !important;
}
@@ -1086,13 +1122,49 @@ textarea:focus {
============================================================================= */
#help-pane {
background: var(--ots-surface-2);
position: fixed;
bottom: 20px;
right: 20px;
z-index: 10000;
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 12px;
}
#help-pane .help-pane-container {
position: relative;
width: 400px;
flex-direction: column;
align-items: flex-start;
border-radius: 4px;
border: 1px solid var(--ots-border);
background: var(--ots-surface-2);
overflow: hidden;
max-height: calc(100vh - 100px);
overflow-y: auto;
}
#help-pane .help-pane-btn {
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
width: 48px;
height: 48px;
border-radius: 50px;
background: var(--ots-primary);
color: #0b1020;
cursor: pointer;
}
#help-pane .help-pane-btn:hover {
background: var(--ots-primary-2);
}
#help-pane .help-pane-btn i {
font-size: 24px;
color: #fff;
}
/* =============================================================================
@@ -1103,8 +1175,8 @@ textarea:focus {
margin: 16px 0 24px;
padding: 12px 16px;
border-radius: var(--ots-radius-md);
background: rgba(79, 140, 255, 0.16);
border: 1px solid rgba(79, 140, 255, 0.45);
background: rgba(var(--ots-primary-rgb), 0.16);
border: 1px solid rgba(var(--ots-primary-rgb), 0.45);
color: var(--ots-text);
}
@@ -1128,8 +1200,8 @@ textarea:focus {
============================================================================= */
:root {
--login-accent: #ff8a00;
--login-panel-bg: linear-gradient(180deg, rgba(8,12,20,0.9), rgba(10,16,28,0.85));
--login-accent: #e87800;
--login-panel-bg: var(--ots-surface-2);
}
body.login, body.login-page, .xibo-login, #login, .login-wrapper {
@@ -1138,9 +1210,7 @@ body.login, body.login-page, .xibo-login, #login, .login-wrapper {
align-items: center;
justify-content: center;
padding: 40px 20px;
background-image: radial-gradient(rgba(255,255,255,0.02) 1px, transparent 1px),
linear-gradient(135deg, rgba(6,16,30,0.6), rgba(8,12,24,0.65));
background-size: 48px 48px, cover;
background: var(--ots-bg);
}
body.login-page .container {
@@ -1159,13 +1229,12 @@ body.login-page .container {
#login-box {
width: 100%;
max-width: 520px;
border-radius: 16px;
border-radius: 12px;
padding: 36px 40px 34px;
background: linear-gradient(180deg, rgba(7,12,22,0.92), rgba(10,16,30,0.9));
border: 1px solid rgba(255,255,255,0.08);
box-shadow: 0 28px 70px rgba(2, 6, 23, 0.55);
background: var(--ots-surface-2);
border: 1px solid var(--ots-border);
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.35);
color: var(--ots-text);
backdrop-filter: blur(14px);
}
.login-card .login-logo,
@@ -1327,34 +1396,23 @@ body.login-page .container {
/* Small screens: compress card padding */
@media (max-width: 520px) {
.login-card, .login-panel { padding: 24px; border-radius: 12px; }
.login-card, .login-panel { padding: 24px; border-radius: 8px; }
.login-card .login-logo .logo-icon { width: 72px; height: 72px; }
}
/* Animated background for login page: subtle moving gradient behind the card */
body.login-page::before {
content: "";
/* Static orange accent bar — brand anchor at the bottom of the login page */
body.login-page::after {
content: '';
position: fixed;
inset: 0;
z-index: 0;
background: linear-gradient(120deg, rgba(14,28,45,0.6), rgba(6,16,30,0.55)),
radial-gradient( circle at 10% 20%, rgba(79,140,255,0.06), transparent 10% ),
radial-gradient( circle at 85% 80%, rgba(255,138,0,0.04), transparent 12% );
background-blend-mode: overlay, normal, normal;
background-size: 200% 200%, 100% 100%, 100% 100%;
filter: blur(22px);
pointer-events: none;
opacity: 0.95;
/* no animation here - blobs will provide the motion */
bottom: 0;
left: 0;
right: 0;
height: 3px;
background: var(--login-accent);
z-index: 10;
}
@keyframes ots-login-bg-shift {
0% { background-position: 0% 50%, 0% 0%, 0% 0%; }
50% { background-position: 100% 50%, 0% 0%, 0% 0%; }
100% { background-position: 0% 50%, 0% 0%, 0% 0%; }
}
/* Bring the login card above the animated background */
/* Bring the login card above the background */
.login-card,
.login-panel,
.auth-card,
@@ -1362,80 +1420,6 @@ body.login-page::before {
#login-box {
position: relative;
z-index: 2;
}
/* Blurred animated color blobs behind the login card */
.ots-login-blob {
position: fixed;
pointer-events: none;
filter: blur(60px) saturate(120%);
opacity: 0.9;
mix-blend-mode: screen;
z-index: 0;
will-change: transform, opacity;
}
.ots-login-blob--1 {
width: 520px;
height: 520px;
left: -8%;
top: -6%;
background: radial-gradient(circle at 30% 30%, rgba(79,140,255,0.65), rgba(79,140,255,0.18) 35%, transparent 50%);
animation: ots-blob-move-1 16s ease-in-out infinite alternate !important;
}
.ots-login-blob--2 {
width: 420px;
height: 420px;
right: 6%;
bottom: 18%;
background: radial-gradient(circle at 60% 40%, rgba(255,138,0,0.45), rgba(255,138,0,0.14) 36%, transparent 55%);
animation: ots-blob-move-2 20s ease-in-out infinite alternate !important;
}
.ots-login-blob--3 {
width: 360px;
height: 360px;
left: 18%;
bottom: -4%;
background: radial-gradient(circle at 40% 60%, rgba(94,200,255,0.28), rgba(94,200,255,0.08) 40%, transparent 60%);
animation: ots-blob-move-3 18s ease-in-out infinite alternate !important;
}
.ots-login-bg {
animation-duration: 10s !important;
}
/* Disable other animations/transitions on the login page so only blobs animate */
body.login-page *,
body.login-page *::before,
body.login-page *::after {
animation: none !important;
transition: none !important;
}
/* Re-enable blob animations specifically (higher specificity) */
.ots-login-blob,
.ots-login-blob--1,
.ots-login-blob--2,
.ots-login-blob--3 {
animation-play-state: running !important;
}
@keyframes ots-blob-move-1 {
0% { transform: translate3d(0,0,0) scale(1); opacity: 0.85; }
100% { transform: translate3d(18px,26px,0) scale(1.06); opacity: 0.7; }
}
@keyframes ots-blob-move-2 {
0% { transform: translate3d(0,0,0) scale(1); opacity: 0.65; }
100% { transform: translate3d(-28px,-18px,0) scale(1.08); opacity: 0.55; }
}
@keyframes ots-blob-move-3 {
0% { transform: translate3d(0,0,0) scale(1); opacity: 0.6; }
100% { transform: translate3d(22px,-20px,0) scale(1.05); opacity: 0.5; }
}
/* EXTRA DEFENSIVE: ensure no white background shows through on long pages */
@@ -1489,16 +1473,16 @@ html[style], body[style] {
}
.ots-upload-dropzone {
border-color: var(--ots-border, #2c3a54);
background: rgba(79,140,255,0.03);
background: rgba(232,120,0,0.03);
}
.ots-upload-dropzone:hover,
.ots-upload-dropzone:focus-visible {
border-color: var(--ots-primary, #4f8cff);
background: rgba(79,140,255,0.07);
border-color: var(--ots-primary, #e87800);
background: rgba(232,120,0,0.07);
}
.ots-upload-dropzone--over {
border-color: var(--ots-primary, #4f8cff) !important;
background: rgba(79,140,255,0.12) !important;
border-color: var(--ots-primary, #e87800) !important;
background: rgba(232,120,0,0.12) !important;
}
.ots-upload-file-item {
background: var(--ots-bg, #0b111a);
@@ -1523,8 +1507,8 @@ html[style], body[style] {
color: var(--ots-text, #e6eefb);
}
.ots-upload-option {
background: rgba(79,140,255,0.04);
border-color: rgba(79,140,255,0.08);
background: rgba(232,120,0,0.04);
border-color: rgba(232,120,0,0.08);
color: var(--ots-text, #e6eefb);
}
.ots-upload-option small {