diff --git a/ots-signs/config.php b/ots-signs/config.php index c8efa74..c47100a 100644 --- a/ots-signs/config.php +++ b/ots-signs/config.php @@ -8,7 +8,7 @@ * Xibo is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or - * any later version. + * any later version. * * Xibo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -17,20 +17,20 @@ * * You should have received a copy of the GNU Affero General Public License * along with Xibo. If not, see . - */ + */ defined('XIBO') or die("Sorry, you are not allowed to directly access this page.
Please press the back button in your browser."); $config = array( - 'theme_name' => 'otssigns', - 'theme_title' => 'OTS Signs', - 'app_name' => 'OTS Signage', - 'theme_url' => 'CMS Homepage', - 'cms_source_url' => 'https://github.com/xibosignage/xibo-cms', - 'cms_install_url' => 'manual/en/install_cms.html', - 'cms_release_notes_url' => 'manual/en/release_notes.html', - 'latest_news_url' => 'http://xibo.org.uk/feed/', - 'client_sendCurrentLayoutAsStatusUpdate_enabled' => false, - 'client_screenShotRequestInterval_enabled' => false, - "view_path" => "../web/theme/custom/ots-signs/views", - 'product_support_url' => 'https://community.xibo.org.uk/c/support' - ); + 'theme_name' => 'ots-signs', + 'theme_title' => 'OTS Signs', + 'app_name' => 'OTS Signage', + 'theme_url' => 'CMS Homepage', + 'cms_source_url' => 'https://github.com/xibosignage/xibo-cms', + 'cms_install_url' => 'manual/en/install_cms.html', + 'cms_release_notes_url' => 'manual/en/release_notes.html', + 'latest_news_url' => 'http://xibo.org.uk/feed/', + 'client_sendCurrentLayoutAsStatusUpdate_enabled' => false, + 'client_screenShotRequestInterval_enabled' => false, + 'view_path' => '../web/theme/custom/ots-signs/views', + 'product_support_url' => 'https://community.xibo.org.uk/c/support' +); diff --git a/ots-signs/css/override-dark.css b/ots-signs/css/override-dark.css deleted file mode 100644 index dfb7588..0000000 --- a/ots-signs/css/override-dark.css +++ /dev/null @@ -1,1515 +0,0 @@ -/* ============================================================================= - OTS SIGNAGE DARK THEME (REBUILT) - 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; - - --ots-bg: #0b111a; - --ots-surface: #141c2b; - --ots-surface-2: #1b2436; - --ots-surface-3: #222c3f; - --ots-border: #2c3a54; - --ots-border-soft: #243047; - --ots-text: #e6eefb; - --ots-text-muted: #a9b6cc; - --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; - --ots-info: #5ec0ff; - - --ots-shadow-lg: 0 14px 30px rgba(0, 0, 0, 0.35); - --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: 4px; - --ots-radius-md: 8px; - --ots-radius-lg: 12px; - - --ots-transition: 160ms ease; - - /* Modal pop-ups */ - --modal-backdrop-bg: rgba(2, 6, 23, 0.55); - --modal-backdrop-blur: 6px; - --modal-bg: #141c2b; - --modal-border: #2c3a54; - --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; - --modal-header-text: #f1f5f9; - --modal-body-bg: #141c2b; - --modal-body-text: #e2e8f0; - --modal-footer-bg: #0f172a; - --modal-footer-border: #2c3a54; - --modal-close-color: #64748b; - --modal-close-hover: #f1f5f9; - --modal-input-bg: #0b111a; - --modal-input-border: #2c3a54; - --modal-input-text: #e6eefb; - --modal-input-focus-border: #e87800; - --modal-input-focus-ring: rgba(var(--ots-primary-rgb), 0.2); -} - -/* ============================================================================= - GLOBAL - ============================================================================= */ - -html, -body { - background: var(--ots-bg); - color: var(--ots-text); -} - -body { - 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, -.nav-link, -.sidebar a { - color: var(--ots-text); - text-decoration: none; - transition: color var(--ots-transition), background var(--ots-transition); -} - -a:hover, -.nav-link:hover, -.sidebar a:hover { - color: var(--ots-primary); -} - -h1, -h2, -h3, -h4, -h5, -h6 { - color: var(--ots-text); - font-weight: 600; -} - -small, -.text-muted { - color: var(--ots-text-muted) !important; -} - -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 - ============================================================================= */ - -#page-wrapper, -#content-wrapper, -.page-content { - background: var(--ots-bg); -} - -.page-content { - padding-top: 24px; -} - -/* ============================================================================= - NAVBAR / TOPBAR - ============================================================================= */ - -.navbar, -.navbar-default { - background: var(--ots-surface-2); - border: 1px solid var(--ots-border); -} - -/* Horizontal nav mode: remove sidebar margins from #content-wrapper */ -.navbar.navbar-expand-lg ~ #content-wrapper { - margin-left: 0 !important; - width: 100% !important; - max-width: 100% !important; - padding-left: 20px !important; - padding-right: 20px !important; -} - -.navbar.navbar-expand-lg ~ #content-wrapper .page-content { - padding-left: 0 !important; - padding-right: 0 !important; -} - -.navbar.navbar-expand-lg ~ #content-wrapper .page-content .row { - margin-left: 0 !important; - margin-right: 0 !important; -} - -.navbar.navbar-expand-lg ~ #content-wrapper .page-content [class*="col-"] { - padding-left: 0 !important; - padding-right: 0 !important; -} - -.navbar.navbar-expand-lg ~ #content-wrapper .page-content > .row > .col-sm-12 { - padding-left: 0 !important; - padding-right: 0 !important; -} - -.navbar.navbar-expand-lg ~ #content-wrapper, -.navbar.navbar-expand-lg ~ #content-wrapper .page-content { - background: var(--ots-bg) !important; - color: var(--ots-text) !important; -} - -.navbar-brand, -.navbar-brand .xibo-logo { - color: var(--ots-text); -} - -.navbar-nav > li > a, -.navbar-nav > .active > a, -.navbar-nav > .open > a { - color: var(--ots-text) !important; - background: transparent !important; -} - -.navbar-nav > li > a:hover { - color: var(--ots-primary) !important; -} - -.navbar-toggler, -.navbar-toggler-side { - color: var(--ots-text); - border: 1px solid var(--ots-border); -} - -/* Topbar nav refinements (dark) */ -.ots-topbar.navbar-nav { - background: transparent; - border: 0; - padding: 0; - margin: 0; - gap: 6px; - height: auto; - align-items: center; -} - -.ots-topbar .nav-link { - display: inline-flex; - align-items: center; - gap: 8px; - padding: 8px 12px; - border-radius: 10px; - color: var(--ots-text); - font-weight: 600; - transition: background var(--ots-transition), color var(--ots-transition); -} - -.ots-topbar .nav-link:hover, -.ots-topbar .nav-item.open .nav-link, -.ots-topbar .nav-item.active .nav-link { - background: rgba(var(--ots-primary-rgb), 0.18); - color: var(--ots-primary); -} - -.ots-topbar .dropdown-menu { - border-radius: 12px; - padding: 8px; - box-shadow: var(--ots-shadow-md); -} - -.ots-topbar .dropdown-item, -.ots-topbar .dropdown-menu a { - display: flex; - align-items: center; - gap: 8px; - border-radius: 8px; - padding: 8px 10px; -} - -.ots-topbar-icon { - width: 16px; - text-align: center; - opacity: 0.85; - font-size: 13px; -} - -/* ============================================================================= - SIDEBAR - ============================================================================= */ - -#sidebar-wrapper { - background: var(--ots-surface); - border-right: 1px solid var(--ots-border); - display: flex; - flex-direction: column; - height: 100vh; - overflow: hidden; -} - -/* OTS sidebar override marker */ -.ots-sidebar-wrapper { - display: flex; - flex-direction: column; - height: 100vh; - background: var(--ots-surface); -} - -/* Sidebar Header */ -.ots-sidebar-header { - display: flex; - align-items: center; - gap: 12px; - padding: 16px; - border-bottom: 1px solid var(--ots-border); - background: var(--ots-surface); -} - -.ots-brand-logo { - width: 40px; - height: 40px; - display: flex; - align-items: center; - justify-content: center; - 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; -} - -.ots-brand-text { - flex: 1; - min-width: 0; -} - -.ots-brand-name { - display: block; - font-size: 14px; - font-weight: 600; - color: var(--ots-text); - letter-spacing: 0.5px; -} - -.ots-sidebar-close { - background: none; - border: none; - color: var(--ots-text-secondary); - cursor: pointer; - padding: 4px; - display: flex; - align-items: center; - justify-content: center; - transition: color var(--ots-transition); - flex-shrink: 0; -} - -.ots-sidebar-close:hover { - color: var(--ots-text); -} - -/* Sidebar Content */ -.ots-sidebar { - flex: 1; - list-style: none; - margin: 0; - padding: 12px 0; - overflow-y: auto; - overflow-x: hidden; -} - -.ots-sidebar li { - margin: 0; - padding: 0; -} - -/* Dark-mode repair overrides: ensure sidebar doesn't draw a vertical divider */ -#sidebar-wrapper, -.ots-sidebar { - border-right: none !important; - box-shadow: none !important; -} - -/* Hide pseudo-elements that might draw a divider */ -.ots-sidebar::before, -.ots-sidebar::after, -#sidebar-wrapper::before, -#sidebar-wrapper::after, -#page-wrapper::before, -#page-wrapper::after { - content: none !important; - display: none !important; - background: transparent !important; - box-shadow: none !important; -} - -/* Sidebar Main Item */ -.ots-sidebar li.sidebar-main > a { - display: flex; - align-items: center; - gap: 12px; - margin: 0 8px; - padding: 10px 12px; - border-radius: var(--ots-radius-sm); - color: var(--ots-text); - text-decoration: none; - transition: background var(--ots-transition), color var(--ots-transition); - font-size: 14px; - font-weight: 500; -} - -.ots-sidebar li.sidebar-main > a:hover { - background: rgba(var(--ots-primary-rgb), 0.12); - color: var(--ots-primary); -} - -.ots-sidebar li.sidebar-main > a.active { - background: rgba(var(--ots-primary-rgb), 0.2); - color: var(--ots-primary); -} - -/* Sidebar Section (Collapsible) */ -.ots-sidebar li.sidebar-section > a.sidebar-section-toggle { - display: flex; - align-items: center; - gap: 12px; - margin: 0 8px; - padding: 10px 12px; - border-radius: var(--ots-radius-sm); - color: var(--ots-text); - text-decoration: none; - transition: background var(--ots-transition), color var(--ots-transition); - font-size: 14px; - font-weight: 500; - cursor: pointer; - background: none; - border: none; - text-align: left; - width: calc(100% - 16px); -} - -.ots-sidebar li.sidebar-section > a.sidebar-section-toggle:hover { - background: rgba(var(--ots-primary-rgb), 0.12); - color: var(--ots-primary); -} - -.ots-sidebar li.sidebar-section > a.sidebar-section-toggle.active { - background: rgba(var(--ots-primary-rgb), 0.12); - color: var(--ots-primary); -} - -.ots-section-toggle-icon { - margin-left: auto; - font-size: 12px; - transition: transform var(--ots-transition); -} - -.ots-sidebar li.sidebar-section > a.sidebar-section-toggle.active .ots-section-toggle-icon { - transform: rotate(180deg); -} - -/* Sidebar Subsection */ -.ots-sidebar .sidebar-subsection { - list-style: none; - margin: 0; - padding: 4px 0; - display: none; - background: rgba(var(--ots-primary-rgb), 0.05); -} - -.ots-sidebar .sidebar-subsection.active { - display: block; -} - -.ots-sidebar .sidebar-subsection li { - margin: 0; - padding: 0; -} - -/* Sidebar List Item */ -.ots-sidebar li.sidebar-list > a { - display: flex; - align-items: center; - gap: 12px; - margin: 2px 12px 2px 28px; - padding: 8px 12px; - border-radius: 4px; - color: var(--ots-text-secondary); - text-decoration: none; - transition: background var(--ots-transition), color var(--ots-transition); - font-size: 13px; -} - -.ots-sidebar li.sidebar-list > a:hover { - background: rgba(var(--ots-primary-rgb), 0.12); - color: var(--ots-primary); -} - -.ots-sidebar li.sidebar-list > a.active { - background: rgba(var(--ots-primary-rgb), 0.15); - color: var(--ots-primary); -} - -/* Navigation Icons and Text */ - -/* ========================================================================== - FORCE DARK BACKGROUND FALLBACKS - Ensure no white areas appear when scrolling or when elements overflow. - This uses high-specificity selectors and !important to override stray - light-background rules from other stylesheets. - ========================================================================== */ - -html, body, #page-wrapper, .ots-main, .ots-content, .page-content, .container { - background-color: var(--color-background) !important; - background: none !important; - color: var(--color-text-primary) !important; -} - -/* Remove or neutralise any pseudo-elements that may paint a light background */ -html::before, html::after, body::before, body::after, #page-wrapper::before, #page-wrapper::after { - background: transparent !important; - content: none !important; -} - -/* Ensure fixed/backdrop layers are dark where appropriate */ -.modal-backdrop, -.modal, -.modal-open, -.ots-shell, -.ots-footer { - background-color: var(--color-background) !important; -} - -/* Defensive: override any explicit white panel backgrounds that leak outside their container */ -.card, .panel, .panel-body, .dashboard-card, .content-card, .ots-sidebar li.sidebar-list.active > a { - background-color: var(--color-surface) !important; - color: var(--color-text-primary) !important; -} -.ots-nav-icon { - width: 16px; - height: 16px; - display: flex; - align-items: center; - justify-content: center; - text-align: center; - opacity: 0.85; - font-size: 14px; - flex-shrink: 0; -} - -.ots-nav-text { - flex: 1; - min-width: 0; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -/* Sidebar Spacer */ -.sidebar-spacer { - height: 12px; - margin-top: auto; -} - -/* Sidebar Footer */ -.ots-sidebar-footer { - display: flex; - align-items: center; - gap: 12px; - padding: 12px 16px; - border-top: 1px solid var(--ots-border); - background: var(--ots-surface); -} - -.ots-user-section { - flex: 1; - min-width: 0; -} - -.ots-user-role { - font-size: 11px; - color: var(--ots-text-secondary); - text-transform: uppercase; - letter-spacing: 0.5px; - margin-bottom: 2px; -} - -.ots-user-name { - font-size: 13px; - font-weight: 500; - color: var(--ots-text); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.ots-user-profile-link { - display: flex; - align-items: center; - justify-content: center; - width: 32px; - height: 32px; - border-radius: 4px; - color: var(--ots-text-secondary); - text-decoration: none; - transition: background var(--ots-transition), color var(--ots-transition); - font-size: 16px; - flex-shrink: 0; -} - -.ots-user-profile-link:hover { - 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(var(--ots-primary-rgb), 0.12); - color: var(--ots-primary); -} - -#sidebar-wrapper .sidebar-title a { - padding: 12px 18px 6px; - color: var(--ots-text-faint); - font-size: 11px; - letter-spacing: 0.08em; - text-transform: uppercase; -} - -/* ============================================================================= - WIDGETS / CARDS - ============================================================================= */ - -.widget, -.card, -.panel, -.modal-content { - background: var(--ots-surface-2); - border: 1px solid var(--ots-border); - border-radius: var(--ots-radius-md); - box-shadow: var(--ots-shadow-sm); -} - -.widget-title, -.panel-heading, -.card-header, -.modal-header { - background: var(--ots-surface-3); - border-bottom: 1px solid var(--ots-border); - color: var(--ots-text); -} - -.widget-body, -.panel-body, -.card-body, -.modal-body { - color: var(--ots-text); -} - -/* ============================================================================= - BUTTONS - ============================================================================= */ - -.btn, -button, -input[type="button"], -input[type="submit"] { - border-radius: var(--ots-radius-sm); - border: 1px solid transparent; - transition: background var(--ots-transition), border var(--ots-transition), color var(--ots-transition); -} - -.btn-default, -.btn-secondary { - background: var(--ots-surface-3); - color: var(--ots-text); - border-color: var(--ots-border); -} - -.btn-default:hover, -.btn-secondary:hover { - background: var(--ots-surface-2); - border-color: var(--ots-primary); - color: var(--ots-primary); -} - -.btn-primary { - background: var(--ots-primary); - border-color: var(--ots-primary-2); - color: #0b1020; -} - -.btn-primary:hover { - background: var(--ots-primary-2); - border-color: var(--ots-primary-2); - color: #0b1020; -} - -.btn-success { - background: var(--ots-success); - border-color: var(--ots-success); - color: #041410; -} - -.btn-warning { - background: var(--ots-warning); - border-color: var(--ots-warning); - color: #1c1200; -} - -.btn-danger { - background: var(--ots-danger); - border-color: var(--ots-danger); - color: #220707; -} - -.btn-info { - background: var(--ots-info); - border-color: var(--ots-info); - color: #07101a; -} - -/* ============================================================================= - FORMS - ============================================================================= */ - -.form-control, -input[type="text"], -input[type="search"], -input[type="email"], -input[type="password"], -select, -textarea { - background: var(--ots-surface); - color: var(--ots-text); - border: 1px solid var(--ots-border); - border-radius: var(--ots-radius-sm); - box-shadow: none; -} - -.form-control:focus, -input[type="text"]:focus, -input[type="search"]:focus, -input[type="email"]:focus, -input[type="password"]:focus, -select:focus, -textarea:focus { - border-color: var(--ots-primary); - box-shadow: 0 0 0 2px rgba(var(--ots-primary-rgb), 0.2); - outline: none; -} - -.input-group-addon { - background: var(--ots-surface-3); - border: 1px solid var(--ots-border); - color: var(--ots-text-muted); -} - -/* ============================================================================= - TABLES / DATATABLES - ============================================================================= */ - -.table, -.table > thead > tr > th, -.table > tbody > tr > td { - color: var(--ots-text); - border-color: var(--ots-border); -} - -.table-striped > tbody > tr:nth-of-type(odd) { - background: rgba(var(--ots-primary-rgb), 0.04); -} - -.table-hover > tbody > tr:hover { - background: rgba(var(--ots-primary-rgb), 0.08); -} - -.dataTables_wrapper .dataTables_length, -.dataTables_wrapper .dataTables_filter, -.dataTables_wrapper .dataTables_info, -.dataTables_wrapper .dataTables_paginate { - color: var(--ots-text-muted) !important; -} - -.dataTables_wrapper .dataTables_filter input, -.dataTables_wrapper .dataTables_length select { - background: var(--ots-surface) !important; - color: var(--ots-text) !important; - border: 1px solid var(--ots-border) !important; -} - -.dataTables_wrapper table { - color: var(--ots-text); -} - -/* ============================================================================= - DROPDOWNS / MENUS - ============================================================================= */ - -.dropdown-menu { - background: var(--ots-surface-2); - border: 1px solid var(--ots-border); - box-shadow: var(--ots-shadow-md); -} - -.dropdown-item, -.dropdown-menu > li > a { - color: var(--ots-text); -} - -.dropdown-item:hover, -.dropdown-menu > li > a:hover { - background: rgba(var(--ots-primary-rgb), 0.12); - color: var(--ots-primary); -} - -/* ============================================================================= - ALERTS / BADGES - ============================================================================= */ - -.alert { - border-radius: var(--ots-radius-sm); - border: 1px solid var(--ots-border); -} - -.alert-success { - background: rgba(42, 212, 164, 0.15); - color: var(--ots-success); -} - -.alert-warning { - background: rgba(244, 184, 96, 0.15); - color: var(--ots-warning); -} - -.alert-danger { - background: rgba(255, 107, 107, 0.15); - color: var(--ots-danger); -} - -.alert-info { - background: rgba(94, 192, 255, 0.15); - color: var(--ots-info); -} - -.badge, -.label { - background: var(--ots-surface-3); - color: var(--ots-text); - border: 1px solid var(--ots-border); -} - -/* ============================================================================= - TABS / PAGINATION - ============================================================================= */ - -.nav-tabs { - border-bottom: 1px solid var(--ots-border); -} - -.nav-tabs > li > a { - color: var(--ots-text-muted); - border: 1px solid transparent; -} - -.nav-tabs > li.active > a, -.nav-tabs > li.active > a:focus, -.nav-tabs > li.active > a:hover { - background: var(--ots-surface-2); - color: var(--ots-text); - border: 1px solid var(--ots-border); - border-bottom-color: transparent; -} - -.pagination > li > a, -.pagination > li > span { - background: var(--ots-surface-2); - border: 1px solid var(--ots-border); - color: var(--ots-text); -} - -.pagination > li > a:hover, -.pagination > li > span:hover { - background: var(--ots-surface-3); - color: var(--ots-primary); -} - -.pagination > .active > a, -.pagination > .active > span { - background: var(--ots-primary); - border-color: var(--ots-primary-2); - color: #0b1020; -} - -/* ============================================================================= - MODALS - ============================================================================= */ - -/* --- Content wrapper --- */ -.modal-content { - border-radius: var(--ots-radius-lg); - background-color: var(--modal-bg, var(--ots-surface)) !important; - color: var(--modal-body-text, var(--ots-text)) !important; - border: 1px solid var(--modal-border, var(--ots-border)) !important; - box-shadow: var(--modal-shadow, var(--ots-shadow-lg)) !important; - overflow: hidden; -} - -/* --- Transparent parents --- */ -.modal, -.modal-header, -.modal-body, -.modal-footer { - color: var(--modal-body-text, var(--ots-text)) !important; -} - -/* --- Header --- */ -.modal-header { - background-color: var(--modal-header-bg, var(--ots-surface)) !important; - border-bottom: 1px solid var(--modal-header-border, var(--ots-border)) !important; - padding: 16px 20px !important; -} - -.modal-title, -.modal-header h4, -.modal-header h5 { - color: var(--modal-header-text, var(--ots-text)) !important; - font-weight: 600; -} - -/* --- Body --- */ -.modal-body { - background-color: var(--modal-body-bg, var(--ots-surface)) !important; - color: var(--modal-body-text, var(--ots-text)) !important; - padding: 20px !important; -} - -/* --- Backdrop --- */ -.modal-backdrop, -.modal-backdrop.show, -.modal-backdrop.in { - background-color: var(--modal-backdrop-bg, rgba(0, 0, 0, 0.3)) !important; - backdrop-filter: blur(var(--modal-backdrop-blur, 4px)) !important; - -webkit-backdrop-filter: blur(var(--modal-backdrop-blur, 4px)) !important; - opacity: 1 !important; -} - -/* --- Footer --- */ -.modal-footer { - background-color: var(--modal-footer-bg, transparent) !important; - border-top: 1px solid var(--modal-footer-border, var(--ots-border)) !important; - padding: 12px 20px !important; -} - -/* Footer buttons — secondary / cancel */ -.modal-footer .btn, -.modal-footer button { - background: var(--modal-body-bg, var(--ots-surface-3)) !important; - color: var(--modal-body-text, var(--ots-text)) !important; - border: 1px solid var(--modal-border, var(--ots-border)) !important; - box-shadow: none !important; - border-radius: var(--ots-radius-sm) !important; - transition: background var(--ots-transition), - color var(--ots-transition), - border-color var(--ots-transition); -} - -.modal-footer .btn:hover, -.modal-footer button:hover { - background: rgba(var(--ots-primary-rgb), 0.08) !important; - color: var(--ots-primary) !important; - border-color: var(--ots-primary) !important; -} - -/* Footer buttons — primary / submit */ -.modal-footer .btn.btn-primary, -.modal-footer button.btn-primary { - background: var(--ots-primary) !important; - color: #0b1020 !important; - border-color: var(--ots-primary-2) !important; - font-weight: 600; -} - -.modal-footer .btn.btn-primary:hover, -.modal-footer button.btn-primary:hover { - background: var(--ots-primary-2) !important; - color: #ffffff !important; -} - -/* Footer buttons — danger */ -.modal-footer .btn.btn-danger { - background: var(--ots-danger) !important; - color: #ffffff !important; - border-color: var(--ots-danger) !important; -} - -/* --- Form controls inside modals --- */ -.modal-body .form-control, -.modal-body input[type="text"], -.modal-body input[type="number"], -.modal-body input[type="email"], -.modal-body input[type="password"], -.modal-body textarea, -.modal-body select { - background-color: var(--modal-input-bg, var(--ots-bg)) !important; - border: 1px solid var(--modal-input-border, var(--ots-border)) !important; - border-radius: var(--ots-radius-sm) !important; - color: var(--modal-input-text, var(--ots-text)) !important; -} - -.modal-body .form-control:focus, -.modal-body input: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(var(--ots-primary-rgb), 0.2)) !important; - outline: none !important; -} - -/* --- Bootstrap Tagsinput / Tokenfield inside modals --- */ -.modal-body .bootstrap-tagsinput, -.modal-body .tagsinput, -.modal-body .tokenfield { - background-color: var(--modal-input-bg, var(--ots-bg)) !important; - border: 1px solid var(--modal-input-border, var(--ots-border)) !important; - border-radius: var(--ots-radius-sm) !important; - color: var(--modal-input-text, var(--ots-text)) !important; - min-height: 36px; - padding: 4px 8px !important; - box-shadow: none !important; - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 4px; -} - -.modal-body .bootstrap-tagsinput:focus-within, -.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(var(--ots-primary-rgb), 0.2)) !important; -} - -.modal-body .bootstrap-tagsinput input, -.modal-body .tagsinput input, -.modal-body .tokenfield input.token-input { - background: transparent !important; - color: var(--modal-input-text, var(--ots-text)) !important; - border: none !important; - box-shadow: none !important; - outline: none !important; - margin: 0 !important; - padding: 2px 4px !important; -} - -.modal-body .bootstrap-tagsinput input::placeholder, -.modal-body .tagsinput input::placeholder, -.modal-body .tokenfield input.token-input::placeholder { - color: var(--ots-text-faint, #7f8aa3) !important; -} - -.modal-body .bootstrap-tagsinput .tag, -.modal-body .bootstrap-tagsinput .badge, -.modal-body .tagsinput .tag, -.modal-body .tokenfield .token { - 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; - line-height: 1.5; -} - -.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, #e87800) !important; - opacity: 0.7; - margin-left: 4px; - cursor: pointer; -} - -.modal-body .bootstrap-tagsinput .tag [data-role="remove"]:hover, -.modal-body .bootstrap-tagsinput .badge [data-role="remove"]:hover, -.modal-body .tokenfield .token .close:hover { - opacity: 1; -} - -/* Global bootstrap-tagsinput theming (outside modals too) */ -.bootstrap-tagsinput, -.tagsinput, -.tokenfield { - background-color: var(--modal-input-bg, var(--ots-bg)) !important; - border: 1px solid var(--modal-input-border, var(--ots-border)) !important; - border-radius: var(--ots-radius-sm) !important; - color: var(--modal-input-text, var(--ots-text)) !important; - box-shadow: none !important; -} - -.bootstrap-tagsinput input, -.tagsinput input, -.tokenfield input.token-input { - background: transparent !important; - color: var(--modal-input-text, var(--ots-text)) !important; -} - -.bootstrap-tagsinput .tag, -.bootstrap-tagsinput .badge, -.tagsinput .tag, -.tokenfield .token { - 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; -} - -/* --- Close button --- */ -.modal-header .close, -.modal-header [data-dismiss="modal"] { - color: var(--modal-close-color, var(--ots-text-muted)) !important; - opacity: 1 !important; - text-shadow: none !important; -} - -.modal-header .close:hover, -.modal-header [data-dismiss="modal"]:hover { - color: var(--modal-close-hover, var(--ots-text)) !important; -} - -/* ============================================================================= - HELP PANE / MISC - ============================================================================= */ - -#help-pane { - 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; -} - -/* ============================================================================= - OTS DASHBOARD MESSAGE - ============================================================================= */ - -.ots-dashboard-message { - margin: 16px 0 24px; - padding: 12px 16px; - border-radius: var(--ots-radius-md); - background: rgba(var(--ots-primary-rgb), 0.16); - border: 1px solid rgba(var(--ots-primary-rgb), 0.45); - color: var(--ots-text); -} - -.ots-dashboard-message__title { - font-weight: 700; - letter-spacing: 0.02em; - text-transform: uppercase; - font-size: 12px; - margin-bottom: 4px; -} - -.ots-dashboard-message__body { - font-size: 13px; - color: var(--ots-text-muted); -} - -/* ============================================================================= - LOGIN / SIGN-IN PAGE - Styles to match the requested sign-in card: centered panel, dark glass - surface, orange accent, soft shadow and modern inputs. - ============================================================================= */ - -:root { - --login-accent: #e87800; - --login-panel-bg: var(--ots-surface-2); -} - -body.login, body.login-page, .xibo-login, #login, .login-wrapper { - min-height: 100vh; - display: flex; - align-items: center; - justify-content: center; - padding: 40px 20px; - background: var(--ots-bg); -} - -body.login-page .container { - width: 100%; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 16px; -} - -.login-card, -.login-panel, -.auth-card, -.xibo-login-box, -#login-box { - width: 100%; - max-width: 520px; - border-radius: 12px; - padding: 36px 40px 34px; - 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); -} - -.login-card .login-logo, -.login-panel .login-logo { - display: flex; - align-items: center; - justify-content: center; - margin-bottom: 18px; -} - -.login-card .login-logo .logo-icon, -.login-panel .login-logo .logo-icon { - width: 92px; - height: 92px; - border-radius: 10px; - background: var(--login-accent); - display: inline-flex; - align-items: center; - justify-content: center; - box-shadow: 0 6px 18px rgba(0,0,0,0.45); -} - -/* Brand text next to logo on login */ -.login-brand { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 10px; - margin-bottom: 18px; -} - -.login-brand .login-logo { - width: 72px; - height: 72px; - display: inline-block; -} - -.login-brand-text { - color: var(--ots-text); - font-size: 1.2rem; - font-weight: 600; - letter-spacing: 0.02em; -} - -.login-card h1, -.login-panel h1 { - text-align: center; - margin: 8px 0 6px 0; - font-size: 28px; - font-weight: 700; -} - -.login-card .lead, -.login-panel .lead { - text-align: center; - color: rgba(226,232,240,0.74); - margin-bottom: 18px; - font-size: 0.95rem; -} - -.login-card .form-group, -.login-panel .form-group { - margin-bottom: 14px; -} - -.login-card input[type="text"], -.login-card input[type="email"], -.login-card input[type="password"], -.login-card .form-control, -.login-panel input[type="text"], -.login-panel input[type="email"], -.login-panel input[type="password"] { - width: 100%; - background: rgba(11, 18, 33, 0.65); - border: 1px solid rgba(148, 163, 184, 0.18); - color: var(--ots-text); - padding: 12px 14px; - border-radius: 10px; - font-size: 0.98rem; - line-height: 1.25; - transition: border-color 180ms ease, box-shadow 180ms ease, background 180ms ease; -} - -.login-card input:focus, -.login-panel input:focus, -.login-card .form-control:focus { - outline: none; - border-color: rgba(255,138,0,0.85); - background: rgba(11, 18, 33, 0.75); - box-shadow: 0 10px 26px rgba(0,0,0,0.38), 0 0 0 5px rgba(255,138,0,0.08); -} - -.login-card input::placeholder, -.login-panel input::placeholder { - color: rgba(255,255,255,0.58); -} - -.login-card input + input, -.login-card input + .form-control, -.login-panel input + input { - margin-top: 10px; -} - -.login-card .form-control[disabled], -.login-card input[disabled] { - opacity: 0.7; -} - -.login-card .btn-signin, -.login-panel .btn-signin, -.login-card .btn-primary.login, -.login-panel .btn-primary.login { - display: inline-flex; - align-items: center; - justify-content: center; - gap: 8px; - width: 100%; - padding: 10px 14px; - background: #f8fafc; - color: #0b1221 !important; - border-radius: 10px; - border: 1px solid rgba(255,255,255,0.8); - font-weight: 600; - box-shadow: 0 10px 22px rgba(2,6,23,0.35); - transition: background 160ms ease, border-color 160ms ease, color 160ms ease, box-shadow 160ms ease, transform 160ms ease; -} - -.login-card .btn-signin .icon, -.login-panel .btn-signin .icon { - display: inline-flex; - align-items: center; - justify-content: center; - width: 18px; - height: 18px; -} - -.login-card .btn-signin:hover, -.login-panel .btn-signin:hover { - background: #ffffff; - border-color: rgba(255,255,255,0.95); - transform: translateY(-1px); -} - -.login-card .btn-signin:focus, -.login-panel .btn-signin:focus { - outline: none; - box-shadow: 0 10px 24px rgba(0,0,0,0.32), 0 0 0 5px rgba(255,138,0,0.18); - border-color: rgba(255,138,0,0.45); -} - -.login-card .forgot-link, -.login-panel .forgot-link { - display: block; - text-align: right; - margin-top: 8px; - color: var(--ots-text-muted); -} - -/* Small screens: compress card padding */ -@media (max-width: 520px) { - .login-card, .login-panel { padding: 24px; border-radius: 8px; } - .login-card .login-logo .logo-icon { width: 72px; height: 72px; } -} - -/* Static orange accent bar — brand anchor at the bottom of the login page */ -body.login-page::after { - content: ''; - position: fixed; - bottom: 0; - left: 0; - right: 0; - height: 3px; - background: var(--login-accent); - z-index: 10; -} - -/* Bring the login card above the background */ -.login-card, -.login-panel, -.auth-card, -.xibo-login-box, -#login-box { - position: relative; - z-index: 2; - - -/* EXTRA DEFENSIVE: ensure no white background shows through on long pages */ -html, body, #page-wrapper, .ots-shell, .ots-main, #content-wrapper, .content-wrapper, .ots-content, .page-content, .container, .container-fluid, .dashboard-page, .dashboard, .dashboard-card, .content-card, .page { - background-color: var(--color-background) !important; - background-image: none !important; - background-repeat: no-repeat !important; - color: var(--color-text-primary) !important; - min-height: 100vh !important; -} - -/* Neutralise any inline styles or late-loaded styles that set white backgrounds */ -*[style] { - background-color: inherit !important; -} - -/* Provide a small utility to detect offending elements visually (useful while debugging) */ -body.debug-white-areas * { - outline: 1px solid rgba(255,0,0,0.04) !important; -} - -/* Strong fallback for modals/backdrops */ -.modal-backdrop, .modal, .modal-open, .ots-footer, .page-footer { - background-color: var(--color-background) !important; -} - -/* Ensure the root html background is also forced dark at the highest level */ -html[style], body[style] { - background-color: var(--color-background) !important; -} - -/* ============================================================================= - OTS UPLOAD MODAL – Dark-mode refinements - Supplements override-styles.twig which uses CSS variables for auto theming. - These rules guarantee the upload modal stays dark when override-dark.css loads. - ============================================================================= */ -.ots-upload-content { - background: var(--ots-surface, #141c2b); - border-color: var(--ots-border, #2c3a54); -} -.ots-upload-header { - background: var(--ots-bg, #0b111a); - border-bottom-color: var(--ots-border, #2c3a54); -} -.ots-upload-title { - color: var(--ots-text, #e6eefb); -} -.ots-upload-body { - background: var(--ots-surface, #141c2b); - color: var(--ots-text, #e6eefb); -} -.ots-upload-dropzone { - border-color: var(--ots-border, #2c3a54); - background: rgba(232,120,0,0.03); -} -.ots-upload-dropzone:hover, -.ots-upload-dropzone:focus-visible { - border-color: var(--ots-primary, #e87800); - background: rgba(232,120,0,0.07); -} -.ots-upload-dropzone--over { - border-color: var(--ots-primary, #e87800) !important; - background: rgba(232,120,0,0.12) !important; -} -.ots-upload-file-item { - background: var(--ots-bg, #0b111a); - border-color: var(--ots-border-soft, #243047); -} -.ots-upload-file-name { - color: var(--ots-text, #e6eefb); -} -.ots-upload-file-meta { - color: var(--ots-text-muted, #a9b6cc); -} -.ots-upload-footer { - background: var(--ots-bg, #0b111a); - border-top-color: var(--ots-border, #2c3a54); -} -.ots-upload-btn-cancel { - color: var(--ots-text-muted, #a9b6cc); - border-color: var(--ots-border, #2c3a54); -} -.ots-upload-btn-cancel:hover { - background: rgba(255,255,255,0.06); - color: var(--ots-text, #e6eefb); -} -.ots-upload-option { - background: rgba(232,120,0,0.04); - border-color: rgba(232,120,0,0.08); - color: var(--ots-text, #e6eefb); -} -.ots-upload-option small { - color: var(--ots-text-muted, #a9b6cc); -} diff --git a/ots-signs/css/override.css b/ots-signs/css/override.css index 9258133..0d94891 100644 --- a/ots-signs/css/override.css +++ b/ots-signs/css/override.css @@ -1,7470 +1,64 @@ -/* ============================================================================ - XIBO CMS MODERN THEME - OTS Signs - Dark Mode Override - Component Styling - ============================================================================ */ +.well { -/* Force dark mode */ -:root { - --color-primary: #e87800; - --ots-primary-rgb: 232, 120, 0; - --color-primary-dark: #c46500; - --color-primary-light: #ff9e20; - --color-primary-lighter: #fff0d9; - --color-success: #10b981; - --color-warning: #f59e0b; - --color-danger: #ef4444; - --color-info: #0ea5e9; - - --color-background: #0f172a; - --color-surface: #1e293b; - --color-surface-elevated: #334155; - --color-border: #475569; - --color-border-light: #1e293b; - --color-text-primary: #ffffff; - --color-text-secondary: #f1f5f9; - --color-text-tertiary: #e2e8f0; - --color-text-inverse: #ffffff; - --color-on-primary: #ffffff; - --ots-sidebar-bg: #08132a; - --ots-sidebar-header-bg: #08132a; - --ots-sidebar-border: rgba(255, 255, 255, 0.08); - --ots-sidebar-link: #f9fbff; - --ots-sidebar-link-hover-bg: rgba(255, 255, 255, 0.08); - --ots-sidebar-link-hover-text: #ffffff; - --ots-sidebar-active-bg: rgba(255, 255, 255, 0.06); - --ots-sidebar-active-text: #ffffff; - --ots-sidebar-active-shadow: 0 8px 18px rgba(15, 23, 42, 0.25); - --ots-sidebar-muted-text: #8ea4c7; - --ots-sidebar-group-bg: rgba(255, 255, 255, 0.03); - --ots-sidebar-group-hover-bg: rgba(255, 255, 255, 0.1); - --ots-sidebar-submenu-bg: rgba(15, 23, 42, 0.6); - --ots-sidebar-submenu-border: rgba(255, 255, 255, 0.9); - --ots-sidebar-submenu-hover-bg: rgba(255, 255, 255, 0.1); - --ots-sidebar-button-bg: rgba(255, 255, 255, 0.08); - --ots-sidebar-button-bg-hover: rgba(255, 255, 255, 0.16); - --ots-sidebar-button-text: #d7e2f8; - --ots-sidebar-collapsed-item-bg: rgba(255, 255, 255, 0.08); - --ots-sidebar-collapsed-item-hover-bg: rgba(255, 255, 255, 0.16); - --ots-sidebar-width: 256px; - --ots-sidebar-collapsed-width: 64px; - --ots-sidebar-header-height: 64px; - --ots-sidebar-item-radius: 8px; - --ots-sidebar-item-height: 44px; - --ots-sidebar-item-padding-x: 12px; - --ots-sidebar-content-gap: 12px; - - /* ── DataTable component tokens ── */ - --dt-header-bg: rgba(15, 23, 42, 0.92); - --dt-header-text: #94a3b8; - --dt-header-border: rgba(148, 163, 184, 0.18); - --dt-row-bg: rgba(15, 23, 42, 0.7); - --dt-row-alt-bg: rgba(30, 41, 59, 0.75); - --dt-row-hover-bg: rgba(var(--ots-primary-rgb), 0.10); - --dt-row-selected-bg: rgba(16, 185, 129, 0.20); - --dt-border: rgba(148, 163, 184, 0.12); - --dt-empty-icon-color: #475569; - --dt-empty-text-color: #64748b; - - /* ── Pagination tokens ── */ - --dt-page-bg: transparent; - --dt-page-text: #94a3b8; - --dt-page-hover-bg: rgba(var(--ots-primary-rgb), 0.12); - --dt-page-hover-text: var(--color-primary-light); - --dt-page-active-bg: var(--color-primary); - --dt-page-active-text: #ffffff; - --dt-page-disabled-text: #334155; - --dt-page-radius: 8px; - - /* ── Status badge tokens ── */ - --badge-success-bg: rgba(16, 185, 129, 0.15); - --badge-success-text: #34d399; - --badge-warning-bg: rgba(245, 158, 11, 0.15); - --badge-warning-text: #fbbf24; - --badge-danger-bg: rgba(239, 68, 68, 0.15); - --badge-danger-text: #f87171; - --badge-info-bg: rgba(14, 165, 233, 0.15); - --badge-info-text: #38bdf8; - --badge-neutral-bg: rgba(148, 163, 184, 0.12); - --badge-neutral-text: #94a3b8; - - /* ── Dashboard stat tile tokens ── */ - --stat-tile-bg: var(--color-surface); - --stat-tile-border: var(--color-border); - --stat-tile-number-color: var(--color-text-primary); - --stat-tile-label-color: var(--color-text-tertiary); - --stat-tile-icon-color: var(--color-primary); - --stat-tile-hover-border: rgba(var(--ots-primary-rgb), 0.4); - --stat-tile-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); - - /* ── FullCalendar override tokens ── */ - --fc-bg: var(--color-surface); - --fc-border: var(--color-border); - --fc-today-bg: rgba(var(--ots-primary-rgb), 0.08); - --fc-event-text: #ffffff; - --fc-toolbar-btn-bg: var(--color-surface-elevated); - --fc-toolbar-btn-text: var(--color-text-primary); - --fc-toolbar-btn-hover-bg: rgba(var(--ots-primary-rgb), 0.12); - --fc-toolbar-btn-active-bg: var(--color-primary); - --fc-toolbar-btn-active-text: #ffffff; - --fc-day-header-text: var(--color-text-secondary); - --fc-day-number-text: var(--color-text-tertiary); - - /* Editor (playlist / layout timeline) */ - --editor-modal-bg: #1a1a2e; - --editor-modal-content-bg: #1e293b; - --editor-modal-header-bg: #0f172a; - --editor-modal-header-text: #f1f5f9; - - /* Modal pop-ups (Bootstrap / Bootbox) */ - --modal-backdrop-bg: rgba(2, 6, 23, 0.55); - --modal-backdrop-blur: 6px; - --modal-bg: #141c2b; - --modal-border: #2c3a54; - --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; - --modal-header-text: #f1f5f9; - --modal-body-bg: #141c2b; - --modal-body-text: #e2e8f0; - --modal-footer-bg: #0f172a; - --modal-footer-border: #2c3a54; - --modal-close-color: #64748b; - --modal-close-hover: #f1f5f9; - --modal-input-bg: #0b111a; - --modal-input-border: #2c3a54; - --modal-input-text: #e6eefb; - --modal-input-focus-border: #e87800; - --modal-input-focus-ring: rgba(var(--ots-primary-rgb), 0.2); - - --editor-body-bg: #1e293b; - --editor-border: #334155; - --editor-text: #e2e8f0; - --editor-text-secondary: #94a3b8; - --editor-toolbar-bg: #0f172a; - --editor-toolbar-text: #e2e8f0; - --editor-toolbar-pane-bg: #1e293b; - --editor-toolbar-pane-text: #e2e8f0; - --editor-footer-controls-bg: #0f172a; - --editor-footer-info-bg: var(--color-primary); - --editor-footer-text: #f1f5f9; - --editor-widget-bg: #334155; - --editor-widget-border: #475569; - --editor-widget-text: #e2e8f0; - --editor-widget-label-bg: #0f172a; - --editor-widget-label-text: #94a3b8; - --editor-widget-hover-bg: #3b4d6b; - --editor-widget-selected-bg: #166534; - --editor-widget-multi-bg: #c2410c; - --editor-widget-multi-hover-bg: #ea580c; - --editor-left-margin-bg: #0f172a; - --editor-timegrid-line: #475569; - --editor-timegrid-text: #64748b; - --editor-timegrid-overlay: rgba(30, 41, 59, 0.7); - --editor-timeline-bg: rgba(30, 41, 59, 0.65); - --editor-scrollbar-track: #1e293b; - --editor-scrollbar-thumb: #475569; - --editor-scrollbar-thumb-hover: #64748b; - --editor-properties-bg: #1e293b; - --editor-properties-border: #166534; - --editor-header-bg: #0f172a; - --editor-back-btn-bg: #0f172a; - --editor-back-btn-text: var(--color-primary-light); - - color-scheme: dark; } -html, +/* dashboard.css */ body { - background-color: var(--color-background); - color: var(--color-text-primary); - overflow-x: hidden !important; - max-width: 100vw !important; + } -/* Minimal mapping so `.dashboard-card` inherits the visual treatment used by widgets/panels. - This allows collapsing one level of DOM without visual regressions. */ -/* Consolidated dashboard-card styling (now in CONSOLIDATED CARD/PANEL/WIDGET section) */ +/*Top header*/ +.row.header { - -/* Floating menus that are moved to body to escape overflowed containers */ -.ots-floating-menu { - border-radius: 8px; - box-shadow: 0 8px 24px rgba(2,6,23,0.6); - background-color: var(--color-surface); - border: 1px solid var(--color-border); - overflow: visible !important; - position: fixed !important; - transform: none !important; -} - -/* Ensure menus that are intentionally floated into `body` are visible - (this targets only menus moved by our JS: `.ots-floating-menu` or - `.dropdown-menu` marked with `data-ots-floating="1`). This avoids - forcing visibility for all dropdowns. */ -.ots-floating-menu, -.dropdown-menu[data-ots-floating="1"] { - display: block !important; - visibility: visible !important; - opacity: 1 !important; -} - -/* Elevated z-index for menus so they render above other panels */ -.ots-floating-menu, .dropdown-menu { - z-index: 99999 !important; -} - -/* Limit aggressive floating/menu overrides to explicit floating menus only. - Avoid forcing `.dropdown-menu` to be `display:block`/`visibility:visible` so - native dropdown behaviour (open/close) is preserved. */ -.ots-notif-menu, -.context-menu, -.row-menu, -.rowMenu, -.menu-popover, -.dataTables_buttons .dropdown-menu, -.ots-floating-menu { - position: fixed !important; - z-index: 2147483647 !important; - transform: none !important; - will-change: auto !important; - pointer-events: auto !important; -} - -/* User menu positioning is handled by floatMenu() which adds .ots-floating-menu. - Only apply fixed positioning when the menu is actively floating. */ -.ots-user-menu.ots-floating-menu { - position: fixed !important; - z-index: 2147483647 !important; - transform: none !important; - will-change: auto !important; - pointer-events: auto !important; -} - -/* The rowMenu th is the empty header for the per-row action dropdown. - Keep it in flow so column count matches tbody, but make it minimal. - The matching td (last-child) holds the action button and must stay visible. - NOTE: No background set here — inherits from .ots-table-card .table thead th rules. */ -th.rowMenu { - width: 40px !important; - min-width: 40px !important; - max-width: 40px !important; - padding: 4px !important; - text-align: center !important; - box-sizing: border-box !important; - border: none !important; -} - -/* Style the action-button td to match the header width */ -table:has(th.rowMenu) > tbody > tr > td:last-child { - width: 40px !important; - min-width: 40px !important; - max-width: 40px !important; - padding: 4px !important; - text-align: center !important; - box-sizing: border-box !important; - overflow: visible !important; -} - -/* Ensure floating menu children aren't clipped (scoped to floated menus only) */ -.ots-floating-menu li, -.ots-floating-menu > li > a, -.ots-floating-menu > li > span, -.ots-floating-menu ul, -.ots-floating-menu div { - overflow: visible !important; -} - -/* Remove transforms inside floating menus that could create stacking context */ -.ots-floating-menu * { - transform: none !important; -} - -/* Light/dark mode toggle */ -#ots-theme-toggle { - display: flex !important; - align-items: center; - gap: 8px; - cursor: pointer; -} - -#ots-theme-toggle:hover { - background-color: rgba(var(--ots-primary-rgb), 0.1) !important; -} - -/* Light mode styles (applied when .ots-light-mode is on html or body) */ -html.ots-light-mode, -body.ots-light-mode { - --color-primary: #e87800; - --ots-primary-rgb: 232, 120, 0; - --color-primary-dark: #c46500; - --color-primary-light: #ff9e20; - --color-primary-lighter: #fff0d9; - --color-success: #059669; - --color-warning: #d97706; - --color-danger: #dc2626; - --color-info: #0284c7; - - --color-background: #f8fafc; - --color-surface: #ffffff; - --color-surface-elevated: #f1f5f9; - --color-border: #e2e8f0; - --color-border-light: #f1f5f9; - --color-text-primary: #0f172a; - --color-text-secondary: #334155; - --color-text-tertiary: #475569; - --color-text-inverse: #0f172a; - --color-on-primary: #ffffff; - - /* OTS core tokens — light mode overrides */ - --ots-bg: #f8fafc; - --ots-surface: #ffffff; - --ots-surface-2: #f1f5f9; - --ots-surface-3: #e2e8f0; - --ots-border: #e2e8f0; - --ots-border-soft: #f1f5f9; - --ots-text: #0f172a; - --ots-text-muted: #475569; - --ots-text-faint: #64748b; - --ots-primary: #e87800; - --ots-primary-2: #c46500; - --ots-success: #059669; - --ots-warning: #d97706; - --ots-danger: #dc2626; - --ots-info: #0284c7; - --ots-shadow-lg: 0 14px 30px rgba(15, 23, 42, 0.12); - --ots-shadow-md: 0 8px 18px rgba(15, 23, 42, 0.08); - --ots-shadow-sm: 0 3px 8px rgba(15, 23, 42, 0.06); - - --ots-sidebar-bg: #f1f5f9; - --ots-sidebar-header-bg: #f1f5f9; - --ots-sidebar-border: #e2e8f0; - --ots-sidebar-link: #334155; - --ots-sidebar-link-hover-bg: rgba(var(--ots-primary-rgb), 0.08); - --ots-sidebar-link-hover-text: #0f172a; - --ots-sidebar-active-bg: #ffffff; - --ots-sidebar-active-text: #0f172a; - --ots-sidebar-active-shadow: 0 8px 18px rgba(15, 23, 42, 0.12); - --ots-sidebar-muted-text: #64748b; - --ots-sidebar-group-bg: rgba(0, 0, 0, 0.03); - --ots-sidebar-group-hover-bg: rgba(0, 0, 0, 0.06); - --ots-sidebar-submenu-bg: rgba(0, 0, 0, 0.04); - --ots-sidebar-submenu-border: #cbd5e1; - --ots-sidebar-submenu-hover-bg: rgba(0, 0, 0, 0.08); - --ots-sidebar-button-bg: rgba(0, 0, 0, 0.04); - --ots-sidebar-button-bg-hover: rgba(0, 0, 0, 0.08); - --ots-sidebar-button-text: #334155; - --ots-sidebar-collapsed-item-bg: rgba(0, 0, 0, 0.04); - --ots-sidebar-collapsed-item-hover-bg: rgba(0, 0, 0, 0.08); - --ots-sidebar-width: 256px; - --ots-sidebar-collapsed-width: 64px; - --ots-sidebar-header-height: 64px; - --ots-sidebar-item-radius: 8px; - --ots-sidebar-item-height: 44px; - --ots-sidebar-item-padding-x: 12px; - - /* ── DataTable component tokens — light mode ── */ - --dt-header-bg: #f1f5f9; - --dt-header-text: #475569; - --dt-header-border: #e2e8f0; - --dt-row-bg: #ffffff; - --dt-row-alt-bg: #f8fafc; - --dt-row-hover-bg: rgba(var(--ots-primary-rgb), 0.06); - --dt-row-selected-bg: rgba(16, 185, 129, 0.12); - --dt-border: #e2e8f0; - --dt-empty-icon-color: #94a3b8; - --dt-empty-text-color: #64748b; - - /* ── Pagination tokens — light mode ── */ - --dt-page-bg: transparent; - --dt-page-text: #475569; - --dt-page-hover-bg: rgba(var(--ots-primary-rgb), 0.08); - --dt-page-hover-text: var(--color-primary-dark); - --dt-page-active-bg: var(--color-primary); - --dt-page-active-text: #ffffff; - --dt-page-disabled-text: #cbd5e1; - --dt-page-radius: 8px; - - /* ── Status badge tokens — light mode ── */ - --badge-success-bg: rgba(5, 150, 105, 0.10); - --badge-success-text: #059669; - --badge-warning-bg: rgba(217, 119, 6, 0.10); - --badge-warning-text: #b45309; - --badge-danger-bg: rgba(220, 38, 38, 0.10); - --badge-danger-text: #dc2626; - --badge-info-bg: rgba(2, 132, 199, 0.10); - --badge-info-text: #0284c7; - --badge-neutral-bg: rgba(100, 116, 139, 0.08); - --badge-neutral-text: #64748b; - - /* ── Dashboard stat tile tokens — light mode ── */ - --stat-tile-bg: #ffffff; - --stat-tile-border: #e2e8f0; - --stat-tile-number-color: #0f172a; - --stat-tile-label-color: #64748b; - --stat-tile-icon-color: var(--color-primary); - --stat-tile-hover-border: rgba(var(--ots-primary-rgb), 0.35); - --stat-tile-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); - - /* ── FullCalendar override tokens — light mode ── */ - --fc-bg: #ffffff; - --fc-border: #e2e8f0; - --fc-today-bg: rgba(var(--ots-primary-rgb), 0.05); - --fc-event-text: #ffffff; - --fc-toolbar-btn-bg: #f1f5f9; - --fc-toolbar-btn-text: #334155; - --fc-toolbar-btn-hover-bg: rgba(var(--ots-primary-rgb), 0.08); - --fc-toolbar-btn-active-bg: var(--color-primary); - --fc-toolbar-btn-active-text: #ffffff; - --fc-day-header-text: #475569; - --fc-day-number-text: #64748b; - - /* Editor (playlist / layout timeline) */ - --editor-modal-bg: #e8e8e8; - --editor-modal-content-bg: #ffffff; - --editor-modal-header-bg: #f1f5f9; - --editor-modal-header-text: #0f172a; - - /* Modal pop-ups (Bootstrap / Bootbox) — light mode */ - --modal-backdrop-bg: rgba(15, 23, 42, 0.25); - --modal-backdrop-blur: 6px; - --modal-bg: #ffffff; - --modal-border: #e2e8f0; - --modal-radius: 12px; - --modal-shadow: 0 24px 64px rgba(15, 23, 42, 0.14), 0 0 0 1px rgba(0, 0, 0, 0.04); - --modal-header-bg: #f8fafc; - --modal-header-border: #e2e8f0; - --modal-header-text: #0f172a; - --modal-body-bg: #ffffff; - --modal-body-text: #334155; - --modal-footer-bg: #f8fafc; - --modal-footer-border: #e2e8f0; - --modal-close-color: #94a3b8; - --modal-close-hover: #0f172a; - --modal-input-bg: #f8fafc; - --modal-input-border: #e2e8f0; - --modal-input-text: #0f172a; - --modal-input-focus-border: #e87800; - --modal-input-focus-ring: rgba(var(--ots-primary-rgb), 0.18); - - --editor-body-bg: #ffffff; - --editor-border: #e2e8f0; - --editor-text: #0f172a; - --editor-text-secondary: #475569; - --editor-toolbar-bg: #1e3a5f; - --editor-toolbar-text: #f1f5f9; - --editor-toolbar-pane-bg: #f3f8ff; - --editor-toolbar-pane-text: #1775f6; - --editor-footer-controls-bg: #0e4694; - --editor-footer-info-bg: var(--color-primary); - --editor-footer-text: #fcfcfc; - --editor-widget-bg: #e8f1fe; - --editor-widget-border: #0e4694; - --editor-widget-text: #121a5e; - --editor-widget-label-bg: transparent; - --editor-widget-label-text: #f3f8ff; - --editor-widget-hover-bg: #d4e4f7; - --editor-widget-selected-bg: #6ec071; - --editor-widget-multi-bg: #eb7857; - --editor-widget-multi-hover-bg: #f09a82; - --editor-left-margin-bg: #e9e9e9; - --editor-timegrid-line: #cecece; - --editor-timegrid-text: #898989; - --editor-timegrid-overlay: rgba(255, 255, 255, 0.7); - --editor-timeline-bg: rgba(255, 255, 255, 0.65); - --editor-scrollbar-track: #f3f8ff; - --editor-scrollbar-thumb: #0e4694; - --editor-scrollbar-thumb-hover: #1264d6; - --editor-properties-bg: #f3f8ff; - --editor-properties-border: #6ec071; - --editor-header-bg: #f1f5f9; - --editor-back-btn-bg: #1e3a5f; - --editor-back-btn-text: #ffffff; - - background-color: var(--color-background); - color: var(--color-text-primary); -} - -body.ots-light-mode .ots-sidebar { - background-color: #f1f5f9 !important; - border-right-color: #e2e8f0 !important; -} - -body.ots-light-mode .ots-sidebar.collapsed .sidebar-group-toggle, -body.ots-light-mode .ots-sidebar.collapsed .sidebar-list > a { - background: rgba(var(--ots-primary-rgb), 0.06) !important; - color: #334155 !important; -} - -body.ots-light-mode .ots-sidebar.collapsed .sidebar-group-toggle:hover, -body.ots-light-mode .ots-sidebar.collapsed .sidebar-list > a:hover { - background: rgba(var(--ots-primary-rgb), 0.12) !important; - color: #0f172a !important; -} - -body.ots-light-mode .ots-sidebar.collapsed .ots-nav-icon { - color: #334155 !important; -} - -body.ots-light-mode .ots-sidebar.collapsed .ots-nav-icon::before, -body.ots-light-mode .ots-sidebar.collapsed .ots-nav-icon.fa::before, -body.ots-light-mode .ots-sidebar.collapsed .fa::before { - color: #334155 !important; -} - -body.ots-light-mode .ots-sidebar li.sidebar-list > a, -body.ots-light-mode .ots-sidebar li.sidebar-main > a { - color: #334155; -} - -body.ots-light-mode .ots-sidebar li.sidebar-list > a:hover { - color: #0f172a; - background-color: rgba(var(--ots-primary-rgb), 0.08); -} - -body.ots-light-mode .sidebar-group-toggle { - color: #334155; - background: rgba(0, 0, 0, 0.03); -} - -body.ots-light-mode .sidebar-group-toggle:hover { - background: rgba(0, 0, 0, 0.06); - color: #0f172a; -} - -body.ots-light-mode .sidebar-group.is-open > .sidebar-group-toggle, -body.ots-light-mode .sidebar-group-toggle[aria-expanded="true"] { - background: #ffffff; - color: #0b1221 !important; -} - -body.ots-light-mode .sidebar-submenu .sidebar-list > a { - background: rgba(0, 0, 0, 0.04); - color: #334155; - border-left-color: #cbd5e1; -} - -/* Light-mode collapsed flyout panel */ -body.ots-light-mode .ots-sidebar.collapsed .sidebar-submenu { - background: #ffffff !important; - border-color: #e2e8f0 !important; - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12) !important; -} - -body.ots-light-mode .ots-sidebar.collapsed .sidebar-submenu .sidebar-list > a { - color: #334155 !important; - background: transparent !important; - border-left: none !important; -} - -body.ots-light-mode .ots-sidebar.collapsed .sidebar-submenu .sidebar-list > a:hover { - background: rgba(var(--ots-primary-rgb), 0.1) !important; - color: #c46500 !important; -} - -body.ots-light-mode .sidebar-header { - border-bottom-color: #e2e8f0; - background: #f1f5f9; -} - -body.ots-light-mode .ots-topbar { - background-color: transparent; - border-bottom: none; -} - -/* (topbar strip is now hidden — light-mode overrides removed) */ - -body.ots-light-mode .ots-topbar .nav-link { - color: #334155; -} - -body.ots-light-mode .ots-topbar .nav-link:hover { - background-color: rgba(var(--ots-primary-rgb), 0.06); - color: var(--ots-primary); -} - -body.ots-light-mode .dashboard-card, -body.ots-light-mode .content-card { - background: linear-gradient(180deg, rgba(255, 255, 255, 0.95), rgba(241, 245, 249, 0.95)); - border-color: #e2e8f0; -} - -body.ots-light-mode .dropdown-menu, -body.ots-light-mode .dropdown-right { - background-color: #ffffff; - border-color: #e2e8f0; - color: #0f172a; -} - -body.ots-light-mode .dropdown-item { - color: #334155; -} - -body.ots-light-mode .dropdown-item:hover, -body.ots-light-mode .dropdown-menu a:hover { - background-color: rgba(var(--ots-primary-rgb), 0.1); - color: var(--ots-primary); -} - -body.ots-light-mode .ots-content { - background-color: var(--color-background); -} - -/* ============================================================================ - ACCESSIBILITY - Focus indicators for keyboard navigation - ============================================================================ */ - -*:focus-visible { - outline: 2px solid var(--color-primary, #e87800); - outline-offset: 2px; -} - -.btn:focus-visible, -.form-control:focus-visible, -.form-select:focus-visible, -.nav-link:focus-visible { - outline: 2px solid var(--color-primary, #e87800); - 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(--color-primary, #e87800); - outline-offset: -2px; - border-radius: 4px; -} - -.sidebar-group-toggle:focus-visible { - outline: 2px solid var(--color-primary, #e87800); - outline-offset: -2px; - border-radius: 4px; -} - -.dropdown-item:focus-visible { - outline: 2px solid var(--color-primary, #e87800); - outline-offset: -2px; - background-color: rgba(var(--ots-primary-rgb), 0.1); -} - -table tbody tr:focus-within { - outline: 1px solid var(--color-primary, #e87800); - outline-offset: -1px; -} - -/* ============================================================================ - THEME ENFORCE - Ensure page backgrounds follow the light/dark CSS variables - This block uses high-specificity rules and !important to override other - theme rules that may hardcode colors so the toggle always reflects - the `--color-*` variables set by `body.ots-light-mode` or :root. - ============================================================================ */ - -html, body, #page-wrapper, .ots-main, .ots-content, .page-content { - background-color: var(--color-background) !important; - color: var(--color-text-primary) !important; -} - -/* Topbar, footer and panels should use surface variables (elevated where appropriate) */ -.ots-topbar, -.ots-footer, -.dashboard-card, -.content-card, -.dropdown-menu, -.dropdown-right, -.modal-content { - background-color: var(--color-surface) !important; - color: var(--color-text-primary) !important; -} - -/* Surface-elevated elements (cards, panels) */ -.card, -.card-body, -.panel, -.panel-body, -.ots-panel, -.modal-body { - background-color: var(--color-surface-elevated) !important; - color: var(--color-text-primary) !important; -} - -/* Ensure sidebar and its components still receive their own overrides */ -.ots-sidebar, -.ots-sidebar .sidebar-header, -.ots-sidebar .sidebar-content { - background-color: var(--ots-sidebar-bg) !important; - color: var(--ots-sidebar-link) !important; -} - - -/* ============================================================================ - SHELL LAYOUT - SIDEBAR + MAIN - ============================================================================ */ - -.ots-shell { - display: flex; - min-height: 100vh; -} - -.ots-sidebar { - position: fixed; - left: 0; - top: 0; - width: max-content !important; - min-width: var(--ots-sidebar-collapsed-width); - max-width: 300px; - height: 100vh; - background-color: var(--ots-sidebar-bg) !important; - padding: 0; - display: flex; - flex-direction: column; - overflow-x: hidden; - overflow-y: auto; - z-index: 1200; - transition: width 200ms ease; -} - -.ots-sidebar .ots-nav-text, -.ots-sidebar .sidebar-submenu .ots-nav-text { - white-space: nowrap; } +/* Sidebar background color */ #sidebar-wrapper { - background-color: var(--ots-sidebar-bg) !important; -} - -.ots-main { - flex: 1; - display: flex; - flex-direction: column; - position: relative; - margin-left: var(--ots-sidebar-actual-width, var(--ots-sidebar-width)) !important; - width: calc(100vw - var(--ots-sidebar-actual-width, var(--ots-sidebar-width))) !important; - max-width: calc(100vw - var(--ots-sidebar-actual-width, var(--ots-sidebar-width))) !important; - transition: margin-left 200ms ease, width 200ms ease, max-width 200ms ease; - overflow-x: hidden !important; - box-sizing: border-box !important; -} - -#page-wrapper { - position: relative; - margin-left: 0 !important; - padding-left: 0 !important; - border: none !important; - box-shadow: none !important; - background-color: var(--color-background) !important; - max-width: 100vw !important; - overflow-x: hidden !important; - box-sizing: border-box !important; -} - -#page-wrapper.active { - padding-left: 0 !important; - margin-left: 0 !important; -} - -/* Sidebar mode only — #page-wrapper is absent in horizontal nav mode */ -#page-wrapper #content-wrapper { - margin-left: var(--ots-sidebar-actual-width, var(--ots-sidebar-width)) !important; - width: calc(100vw - var(--ots-sidebar-actual-width, var(--ots-sidebar-width))) !important; - max-width: calc(100vw - var(--ots-sidebar-actual-width, var(--ots-sidebar-width))) !important; - transition: margin-left 200ms ease, width 200ms ease, max-width 200ms ease; - padding-left: var(--ots-sidebar-content-gap) !important; - padding-right: 16px !important; - border-left: none !important; - box-shadow: none !important; - outline: none !important; - overflow-x: hidden !important; - box-sizing: border-box !important; -} - -/* Base styles for #content-wrapper in all modes */ -#content-wrapper { - border-left: none !important; - box-shadow: none !important; - outline: none !important; - overflow-x: hidden !important; - box-sizing: border-box !important; -} - -/* --- 14a. No-nav pages (layout designer, etc.) – remove sidebar spacing -- */ -#content-wrapper.no-nav { - margin-left: 0 !important; - width: 100% !important; - max-width: 100% !important; - padding: 0 !important; -} - -#content-wrapper.no-nav .page-content { - padding: 0 !important; - margin: 0 !important; -} - -#content-wrapper.no-nav .page-content .row { - margin: 0 !important; - padding: 0 !important; -} - -#content-wrapper.no-nav .page-content [class*="col-"] { - margin: 0 !important; - padding: 0 !important; -} - -/* --- 14b. Layout editor: reset OTS navbar styling so Xibo's bundled editor CSS - controls the top bar appearance unimpeded. -------------------------------- */ -body.editor-opened .navbar, -body.editor-opened .navbar-default, -#layout-editor .navbar, -#layout-editor .navbar-default { - background: transparent !important; - border: none !important; - box-shadow: none !important; -} - -/* --- 14c. Hide the page behind the editor (body class set by JS) --------- */ -body.ots-playlist-editor-active .ots-sidebar { - visibility: hidden !important; -} - -body.ots-playlist-editor-active .ots-topbar { - visibility: hidden !important; -} - -body.ots-playlist-editor-active .ots-page-actions { - display: none !important; -} - -body.ots-playlist-editor-active #help-pane { - display: none !important; -} - -body.ots-playlist-editor-active .page-content > .row > .col-sm-12 > *:not(#editor-container):not(#layout-editor):not(#playlist-editor):not(.loading-overlay) { - display: none !important; -} - -body.ots-playlist-editor-active #content-wrapper, -body.ots-playlist-editor-active .ots-main { - margin-left: 0 !important; - width: 100% !important; - max-width: 100% !important; - padding: 0 !important; - overflow: visible !important; -} - -body.ots-playlist-editor-active .ots-content, -body.ots-playlist-editor-active .page-content { - padding-left: 0 !important; - padding-right: 0 !important; -} - -body.ots-playlist-editor-active .page-content .row, -body.ots-playlist-editor-active .page-content [class*="col-"] { - margin-left: 0 !important; - margin-right: 0 !important; - padding-left: 0 !important; - padding-right: 0 !important; -} - -/* Collapsed: shift content to match the narrow sidebar */ -body.ots-sidebar-collapsed .ots-main, -body.ots-sidebar-collapsed #content-wrapper, -html.ots-sidebar-collapsed .ots-main, -html.ots-sidebar-collapsed #content-wrapper { - margin-left: var(--ots-sidebar-collapsed-width) !important; - width: calc(100vw - var(--ots-sidebar-collapsed-width)) !important; - max-width: calc(100vw - var(--ots-sidebar-collapsed-width)) !important; -} - -.ots-content { - flex: 1; - padding: 32px 16px 32px var(--ots-sidebar-content-gap); - overflow-y: auto; - overflow-x: hidden !important; - max-width: 100% !important; - box-sizing: border-box !important; -} - -/* Consistent left gap between sidebar and page content */ -.page-content { - padding-left: 0 !important; - max-width: 100% !important; - overflow-x: hidden !important; - box-sizing: border-box !important; -} - -/* Remove bootstrap gutters for main content so it sits flush against sidebar */ -.ots-main .page-content .row { - margin-left: 0 !important; - margin-right: 0 !important; - max-width: 100% !important; - overflow-x: hidden !important; -} - -.ots-main .page-content [class*="col-"] { - padding-left: 0 !important; - padding-right: 0 !important; -} - -.ots-main #content-wrapper { - padding-left: var(--ots-sidebar-content-gap) !important; -} - -.ots-main .page-content { - padding-left: 0 !important; -} - -.ots-main .ots-content { - padding-left: var(--ots-sidebar-content-gap) !important; -} - -/* Strongly enforce no left gap for content children (not #content-wrapper itself) */ -#content-wrapper .page-content, -#content-wrapper .page-content .row, -#content-wrapper .page-content [class*="col-"] { - margin-left: 0 !important; - padding-left: 0 !important; -} - -/* Ensure page header and meta area align flush */ -.page-header { - margin-left: 0 !important; - padding-left: 0 !important; -} - -/* Prevent XiboGrid, folder grids, and data containers from causing page overflow */ -.XiboGrid, -.grid-with-folders-container, -.XiboData, -#datatable-container { - max-width: 100% !important; - overflow-x: auto !important; - box-sizing: border-box !important; -} - -/* ============================================================================ - TOPBAR STRIP — HIDDEN - The old full-width topbar is no longer shown. The notification bell and - user menu now live in .ots-page-actions (fixed top-right on every page). - ============================================================================ */ -.row.header.header-side, -.ots-topbar-strip { - display: none !important; - height: 0 !important; - margin: 0 !important; - padding: 0 !important; - overflow: hidden !important; - border: none !important; - box-shadow: none !important; -} - -/* ============================================================================ - PAGE ACTIONS — top-right cluster (bell + user icon) - ============================================================================ */ -.ots-page-actions { - position: absolute; - top: 14px; - right: 20px; - z-index: 1100; - display: flex; - align-items: center; - gap: 2px; - background: var(--color-surface-elevated); - border: 1px solid var(--color-border); - border-radius: 8px; - padding: 3px 4px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.10); -} - -/* Each action inside the cluster — NO position:relative so dropdowns - anchor to .ots-page-actions (position:fixed) instead */ -.ots-page-actions .ots-topbar-action { - display: inline-flex !important; - align-items: center !important; - position: static !important; -} - -.ots-page-actions .ots-topbar-action .nav-item, -.ots-page-actions .ots-topbar-action .dropdown, -.ots-page-actions .ots-topbar-action > div { - display: inline-flex !important; - align-items: center !important; - position: static !important; -} - -.ots-page-actions .ots-topbar-action .nav-link { - display: inline-flex !important; - align-items: center !important; - justify-content: center !important; - width: 28px !important; - height: 28px !important; - padding: 0 !important; - border-radius: 6px !important; - color: var(--color-text-secondary) !important; - transition: all 150ms ease !important; - border: none !important; - background: transparent !important; -} - -.ots-page-actions .ots-topbar-action .nav-link:hover { - background-color: rgba(var(--ots-primary-rgb), 0.08) !important; - color: var(--color-primary) !important; -} - -.ots-page-actions .ots-topbar-action .ots-topbar-icon { - display: flex !important; - align-items: center !important; - justify-content: center !important; - width: 18px !important; - height: 18px !important; - font-size: 16px !important; -} - -.ots-page-actions .ots-topbar-action img.nav-avatar { - display: block !important; - width: 20px !important; - height: 20px !important; - border-radius: 50% !important; - object-fit: cover !important; - border: 1px solid transparent !important; - transition: border-color 150ms ease !important; -} - -.ots-page-actions .ots-topbar-action .nav-link:hover img.nav-avatar { - border-color: var(--color-primary) !important; -} - -/* Dropdown menus from the page actions cluster */ -.ots-page-actions .dropdown-menu { - position: absolute !important; - top: 100% !important; - right: 0 !important; - left: auto !important; - margin-top: 0 !important; - min-width: 200px !important; - background-color: var(--color-surface-elevated) !important; - border: 1px solid var(--color-border) !important; - border-radius: 10px !important; - box-shadow: 0 12px 36px rgba(0, 0, 0, 0.25) !important; - padding: 6px 0 !important; - z-index: 3000 !important; - overflow: visible !important; -} - -/* Bridge the gap between the pill and dropdown so it looks connected */ -.ots-page-actions .dropdown-menu::before { - content: '' !important; - display: block !important; - position: absolute !important; - top: -4px !important; - right: 8px !important; - width: 48px !important; - height: 4px !important; - background: transparent !important; -} - -.ots-page-actions .dropdown-item, -.ots-page-actions .dropdown-menu a { - display: flex !important; - align-items: center !important; - gap: 8px !important; - padding: 8px 14px !important; - margin: 1px 6px !important; - border-radius: 6px !important; - color: var(--color-text-secondary) !important; - font-size: 13px !important; - font-weight: 500 !important; - transition: all 150ms ease !important; - text-decoration: none !important; -} - -.ots-page-actions .dropdown-item:hover, -.ots-page-actions .dropdown-menu a:hover { - background-color: rgba(var(--ots-primary-rgb), 0.08) !important; - color: var(--color-primary) !important; -} - -/* Light mode adjustments for the actions cluster */ -body.ots-light-mode .ots-page-actions { - background: #ffffff; - border-color: #e2e8f0; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); -} - -/* ============================================================================ - USER MENU — standalone styles that apply whether the menu is inside - .ots-page-actions or floated to by floatMenu(). - ============================================================================ */ - -/* When the menu lives in (permanently moved there by initDropdowns), - it's hidden by default and shown only via .ots-user-menu-open. */ -.ots-user-menu.ots-user-menu-body { - position: fixed !important; - display: none !important; - z-index: 2147483647 !important; - transform: none !important; - pointer-events: auto !important; -} - -.ots-user-menu.ots-user-menu-body.ots-user-menu-open { - display: block !important; - visibility: visible !important; - opacity: 1 !important; - animation: otsUserMenuIn 120ms ease-out; -} - -@keyframes otsUserMenuIn { - from { opacity: 0; transform: translateY(-6px); } - to { opacity: 1; transform: translateY(0); } -} - -/* Visual style — applies regardless of where the element is in the DOM */ -.ots-user-menu { - min-width: 200px !important; - background-color: var(--color-surface-elevated) !important; - border: 1px solid var(--color-border) !important; - border-radius: 10px !important; - box-shadow: 0 12px 36px rgba(0, 0, 0, 0.25) !important; - padding: 6px 0 !important; - overflow: visible !important; -} - -.ots-user-menu .dropdown-header { - color: var(--color-text-primary) !important; - font-size: 13px !important; - font-weight: 600 !important; - padding: 8px 14px !important; - white-space: nowrap !important; -} - -.ots-user-menu .dropdown-divider { - border-top: 1px solid var(--color-border) !important; - margin: 4px 0 !important; -} - -.ots-user-menu .dropdown-item, -.ots-user-menu a { - display: flex !important; - align-items: center !important; - gap: 8px !important; - padding: 8px 14px !important; - margin: 1px 6px !important; - border-radius: 6px !important; - color: var(--color-text-secondary) !important; - font-size: 13px !important; - font-weight: 500 !important; - transition: all 150ms ease !important; - text-decoration: none !important; -} - -.ots-user-menu .dropdown-item:hover, -.ots-user-menu a:hover { - background-color: rgba(var(--ots-primary-rgb), 0.08) !important; - color: var(--color-primary) !important; -} - -body.ots-light-mode .ots-user-menu { - background-color: #ffffff !important; - border-color: #e2e8f0 !important; - box-shadow: 0 12px 36px rgba(0, 0, 0, 0.12) !important; -} - -body.ots-light-mode .ots-user-menu .dropdown-item, -body.ots-light-mode .ots-user-menu a { - color: #334155 !important; -} - -body.ots-light-mode .ots-user-menu .dropdown-item:hover, -body.ots-light-mode .ots-user-menu a:hover { - background-color: rgba(var(--ots-primary-rgb), 0.1) !important; - color: var(--ots-primary) !important; -} - -/* ============================================================================ - HORIZONTAL NAV MODE — when .navbar.navbar-expand-lg is present there is no - sidebar, so #content-wrapper must not have the sidebar margin/width offsets. - The page background follows the current light/dark theme variables. - ============================================================================ */ -.navbar.navbar-expand-lg ~ #content-wrapper { - margin-left: 0 !important; - width: 100% !important; - max-width: 100% !important; - padding-left: 20px !important; - padding-right: 20px !important; -} - -.navbar.navbar-expand-lg ~ #content-wrapper .page-content { - padding-left: 0 !important; - padding-right: 0 !important; -} - -.navbar.navbar-expand-lg ~ #content-wrapper .page-content .row { - margin-left: 0 !important; - margin-right: 0 !important; -} - -.navbar.navbar-expand-lg ~ #content-wrapper .page-content [class*="col-"] { - padding-left: 0 !important; - padding-right: 0 !important; -} - -.navbar.navbar-expand-lg ~ #content-wrapper .page-content > .row > .col-sm-12 { - padding-left: 0 !important; - padding-right: 0 !important; -} - -.navbar.navbar-expand-lg ~ #content-wrapper .page-header { - margin-left: 0 !important; - padding-left: 0 !important; -} - -/* Ensure page background follows the theme when horizontal nav is active */ -.navbar.navbar-expand-lg ~ #content-wrapper, -.navbar.navbar-expand-lg ~ #content-wrapper .page-content { - background-color: var(--color-background) !important; - color: var(--color-text-primary) !important; -} - -/* Light-mode overrides for horizontal nav page area */ -body.ots-light-mode .navbar.navbar-expand-lg ~ #content-wrapper, -body.ots-light-mode .navbar.navbar-expand-lg ~ #content-wrapper .page-content { - background-color: var(--color-background) !important; - color: var(--color-text-primary) !important; -} - -/* Horizontal navbar should also follow the theme */ -body.ots-light-mode .navbar.navbar-expand-lg { - background-color: var(--color-surface) !important; - border-color: var(--color-border) !important; - color: var(--color-text-primary) !important; -} - -body.ots-light-mode .navbar.navbar-expand-lg .nav-link, -body.ots-light-mode .navbar.navbar-expand-lg .navbar-nav > li > a { - color: var(--color-text-secondary) !important; -} - -body.ots-light-mode .navbar.navbar-expand-lg .nav-link:hover, -body.ots-light-mode .navbar.navbar-expand-lg .navbar-nav > li > a:hover { - color: var(--color-primary) !important; -} - -.page-header { - background: transparent !important; - box-shadow: none !important; -} - -.ots-footer { - border-top: 1px solid var(--color-border); - padding: 16px 32px; - background-color: var(--color-surface-elevated); - text-align: center; - color: var(--color-text-primary); -} - -/* Responsive sidebar */ -@media (max-width: 768px) { - .ots-sidebar { - transform: translateX(-100%); - transition: transform var(--transition-base); - width: 280px; - } - .ots-sidebar.active { - transform: translateX(0); - box-shadow: 2px 0 8px rgba(0, 0, 0, 0.3); - } - - .ots-main { - margin-left: 0 !important; - } - - .ots-content { - color: var(--color-text-primary); - } -} - -/* Responsive helpers for paged selects and other inline-width controls */ -.pagedSelect { - min-width: 12.5rem; /* 200px */ -} - -@media (max-width: 600px) { - .pagedSelect { - min-width: auto; - width: 100%; - box-sizing: border-box; - } -} - -/* ============================================================================ - SIDEBAR STYLES - ============================================================================ */ - -.sidebar-header { - padding: 12px 16px; - border-bottom: 1px solid var(--color-border); - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; - flex-shrink: 0; - height: var(--ots-sidebar-header-height); -} - -.brand-link { - display: flex; - align-items: center; - gap: 12px; - color: var(--color-text-primary); - font-weight: 700; - font-size: 16px; - text-decoration: none; - flex: 1; -} - -.brand-icon { - width: 40px; - height: 40px; - display: flex; - align-items: center; - justify-content: center; - font-size: 24px; - flex-shrink: 0; -} - -.sidebar-content { - flex: 1; - padding: 8px 0; - overflow-y: auto; - min-height: 0; -} - -.sidebar-nav { - list-style: none; - margin: 0; - padding: 8px 0 16px; -} - -.sidebar-nav li { - display: block; - margin-top: 6px; -} - -/* Compatibility: Xibo sidebar markup uses `sidebar-list`, `sidebar-main`, `sidebar-title`. - Map those into the modern `.nav-item/.nav-text/.nav-icon` style system so styles apply. -*/ -.ots-sidebar li.sidebar-list > a, -.ots-sidebar li.sidebar-main > a, -.ots-sidebar li.sidebar-title > a { - display: flex; - align-items: center; - gap: 12px; - padding: 8px var(--ots-sidebar-item-padding-x); - color: var(--ots-sidebar-link); - text-decoration: none; - transition: all var(--transition-fast); - position: relative; - font-size: 14px; - font-weight: 500; - border-left: 2px solid transparent; - margin: 3px 0; - border-radius: var(--ots-sidebar-item-radius); - min-height: var(--ots-sidebar-item-height); - line-height: 1.25; - width: 100%; - box-sizing: border-box; - padding-right: 48px; /* reserve space for caret */ - text-indent: 0; - float: none; -} - -/* Force readable text in sidebar links */ -.ots-sidebar a, -.ots-sidebar .ots-nav-text { - color: var(--ots-sidebar-link); -} - -.ots-sidebar li.sidebar-list > a:hover { - color: var(--ots-sidebar-link-hover-text); - background-color: var(--ots-sidebar-link-hover-bg); -} - -.ots-sidebar li.sidebar-list.active > a, -.ots-sidebar li.sidebar-list > a.active, -.ots-sidebar li.sidebar-main.active > a, -.ots-sidebar li.sidebar-main > a.active { - color: var(--ots-sidebar-active-text); - background-color: var(--ots-sidebar-active-bg); - border-left-color: transparent; - font-weight: 600; - box-shadow: var(--ots-sidebar-active-shadow); -} - -.ots-sidebar li.sidebar-list.active > a .ots-nav-text, -.ots-sidebar li.sidebar-list > a.active .ots-nav-text, -.ots-sidebar li.sidebar-main.active > a .ots-nav-text, -.ots-sidebar li.sidebar-main > a.active .ots-nav-text { - color: var(--ots-sidebar-active-text); -} - -/* Stronger active state rules to ensure the currently active page is visibly - highlighted regardless of other theme CSS. Covers both `li.active > a` and - `a.active` patterns as well as collapsed sidebar appearance. */ -.ots-sidebar li.sidebar-list.active > a, -.ots-sidebar li.sidebar-list > a.active, -#sidebar-wrapper .sidebar-list a.active, -.ots-sidebar li.sidebar-main.active > a, -.ots-sidebar li.sidebar-main > a.active, -.ots-sidebar .sidebar-list > a[aria-current="page"] { - background-color: var(--ots-sidebar-active-bg) !important; - color: var(--ots-sidebar-active-text) !important; - border-left-color: transparent !important; - font-weight: 600 !important; - box-shadow: var(--ots-sidebar-active-shadow) !important; -} - -/* Ensure the icon in the active link also uses active text color */ -.ots-sidebar li.sidebar-list.active > a .ots-nav-icon, -.ots-sidebar li.sidebar-list > a.active .ots-nav-icon, -#sidebar-wrapper .sidebar-list a.active .ots-nav-icon { - color: var(--ots-sidebar-active-text) !important; -} - -/* Collapsed sidebar: active item highlight */ -.ots-sidebar.collapsed .sidebar-list > a.active, -.ots-sidebar.collapsed .sidebar-group-toggle.active { - background: var(--ots-sidebar-active-bg) !important; - color: var(--ots-sidebar-active-text) !important; -} -.ots-sidebar.collapsed .sidebar-list > a.active .ots-nav-icon, -.ots-sidebar.collapsed .sidebar-group-toggle.active .ots-nav-icon { - color: var(--ots-sidebar-active-text) !important; -} - - -.ots-sidebar .ots-nav-icon { - width: 28px; - height: 28px; - display: flex !important; - align-items: center; - justify-content: center; - flex-shrink: 0; - font-size: 16px; - color: currentColor; - margin: 0; - text-align: center; - line-height: 1; -} - -.ots-sidebar .ots-nav-text { - font-size: 14px; - font-weight: 500; - flex: 1; - line-height: 1.2; -} - -.sidebar-group-toggle .ots-nav-icon, -.ots-sidebar-nav .ots-nav-icon { - justify-self: start; -} - -.ots-sidebar li.sidebar-title > a { - display: block; - font-size: 10px; - font-weight: 700; - text-transform: uppercase; - color: var(--ots-sidebar-muted-text); - letter-spacing: 0.12em; - padding: 12px 14px 4px; - margin: 8px 0 0; - min-height: auto; - line-height: 1; -} - -.brand-logo { - width: 40px; - height: 40px; - object-fit: contain; -} - -.brand-text { - color: var(--color-text-primary); - font-size: 18px; - font-weight: 600; - letter-spacing: 0.02em; -} - -.sidebar-header { - padding: 12px 16px; - border-bottom: 1px solid var(--ots-sidebar-border); - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; - flex-shrink: 0; - height: var(--ots-sidebar-header-height); - box-sizing: border-box; - position: relative; - background: var(--ots-sidebar-header-bg); - z-index: 1; -} - -.sidebar-collapse-btn { - width: 32px; - height: 32px; - border-radius: 8px; - border: 0; - background: var(--ots-sidebar-button-bg); - color: var(--ots-sidebar-button-text); - display: inline-flex; - align-items: center; - justify-content: center; - cursor: pointer; - transition: all var(--transition-fast); -} - -.sidebar-collapse-btn:hover { - background: var(--ots-sidebar-button-bg-hover); - color: var(--ots-sidebar-link-hover-text); -} - -/* Expand button - visible only when collapsed */ -.sidebar-expand-btn { - width: 32px; - height: 32px; - border-radius: 8px; - border: 0; - background: var(--ots-sidebar-button-bg); - color: var(--ots-sidebar-button-text); - display: none; - align-items: center; - justify-content: center; - cursor: pointer; - transition: all var(--transition-fast); -} - -.sidebar-expand-btn:hover { - background: var(--ots-sidebar-button-bg-hover); - color: var(--ots-sidebar-link-hover-text); -} - -.ots-sidebar.collapsed .sidebar-expand-btn { - display: inline-flex !important; -} - -.ots-sidebar.collapsed .sidebar-collapse-btn-visible { - display: none !important; -} - -.ots-sidebar.collapsed { - width: var(--ots-sidebar-collapsed-width) !important; - overflow: visible !important; /* allow popout menus to escape */ -} - -/* When collapsed the sidebar-content must also allow flyout menus to escape */ -.ots-sidebar.collapsed .sidebar-content { - overflow: visible !important; -} - -/* Ensure parent wrapper doesn't clip flyout menus and doesn't create a visible bar. - The sidebar is position:fixed so this wrapper should be invisible in the flow. - Using display:contents so the sidebar inside still renders but the wrapper - itself produces no box at all — eliminating the black bar. */ -.navbar-collapse-side, -.navbar-collapse-side.collapse, -#navbar-collapse-1 { - display: contents !important; - overflow: visible !important; - width: 0 !important; - min-width: 0 !important; - max-width: 0 !important; - height: 0 !important; - max-height: 0 !important; - padding: 0 !important; - margin: 0 !important; - border: none !important; - background: transparent !important; - box-shadow: none !important; - outline: none !important; -} - -.ots-sidebar.collapsed .brand-text, -.ots-sidebar.collapsed > .sidebar-content > .ots-sidebar-nav > .sidebar-group > .sidebar-group-toggle > .ots-nav-text, -.ots-sidebar.collapsed > .sidebar-content > .ots-sidebar-nav > .sidebar-list > a > .ots-nav-text, -.ots-sidebar.collapsed .sidebar-group-caret, -.ots-sidebar.collapsed .user-details, -.ots-sidebar.collapsed .sidebar-header .sidebar-collapse-btn, -.ots-sidebar.collapsed .brand-link .brand-text { - display: none !important; -} - -/* ── Collapsed sidebar: flyout submenu on hover ────────────────────────── - When collapsed, submenus are hidden by default and shown as floating - panels anchored to the right of the sidebar icon on hover. - We deliberately do NOT use display:none here — the JS toggle also sets - inline display, so we use visibility + opacity + pointer-events to hide - the panel and then override on :hover. This avoids the inline - display:none set by JS from blocking the CSS :hover rule. - ─────────────────────────────────────────────────────────────────────── */ -.ots-sidebar.collapsed .sidebar-submenu { - /* Positioning */ - position: absolute !important; - left: 100% !important; - top: 0 !important; - margin-left: 4px !important; - z-index: 10000 !important; - - /* Sizing */ - min-width: 220px !important; - width: max-content !important; - max-height: 80vh !important; - overflow-y: auto !important; - - /* Hidden by default (visibility so :hover can override inline display) */ - visibility: hidden !important; - opacity: 0 !important; - pointer-events: none !important; - - /* Appearance */ - background: var(--color-surface-elevated, #334155) !important; - border: 1px solid var(--color-border, #475569) !important; - border-radius: 8px !important; - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35) !important; - padding: 0 0 8px 0 !important; - list-style: none !important; - - transition: opacity 0.15s ease, visibility 0.15s ease !important; -} - -/* Flyout: show submenu on hover — uses visibility/opacity so it works - even when JS has set an inline display:none or display:block */ -.ots-sidebar.collapsed .sidebar-group:hover > .sidebar-submenu, -.ots-sidebar.collapsed .sidebar-group.flyout-open > .sidebar-submenu { - display: block !important; - visibility: visible !important; - opacity: 1 !important; - pointer-events: auto !important; -} - -/* ── Flyout header (category icon + name) ──────────────────────────── */ -.flyout-header { - display: none; /* hidden in expanded sidebar */ -} - -.ots-sidebar.collapsed .sidebar-submenu .flyout-header { - display: flex !important; - flex-direction: row !important; - align-items: center !important; - gap: 10px !important; - padding: 12px 16px !important; - margin: 0 !important; - border-bottom: none !important; - background: var(--color-primary, #e87800) !important; - pointer-events: none !important; - user-select: none !important; - white-space: nowrap !important; - list-style: none !important; - border-radius: 8px 8px 0 0 !important; - width: 100% !important; - box-sizing: border-box !important; -} - -.ots-sidebar.collapsed .sidebar-submenu .flyout-header-icon { - display: inline-flex !important; - visibility: visible !important; - align-items: center !important; - justify-content: center !important; - width: 22px !important; - height: 22px !important; - font-size: 16px !important; - color: #ffffff !important; - opacity: 1 !important; - flex-shrink: 0 !important; - order: -1 !important; -} - -.ots-sidebar.collapsed .sidebar-submenu .flyout-header-text { - display: inline !important; - visibility: visible !important; - font-size: 14px !important; - font-weight: 700 !important; - text-transform: none !important; - letter-spacing: 0.01em !important; - color: #ffffff !important; - opacity: 1 !important; - width: auto !important; - overflow: visible !important; -} - -/* Light mode flyout header — keep the same primary banner */ -body.ots-light-mode .ots-sidebar.collapsed .sidebar-submenu .flyout-header { - background: var(--color-primary, #e87800) !important; - border-bottom: none !important; -} - -body.ots-light-mode .ots-sidebar.collapsed .sidebar-submenu .flyout-header-icon { - color: #ffffff !important; -} - -body.ots-light-mode .ots-sidebar.collapsed .sidebar-submenu .flyout-header-text { - color: #ffffff !important; -} - -/* Flyout submenu
  • — full width, no centering */ -.ots-sidebar.collapsed .sidebar-submenu .sidebar-list { - display: block !important; - width: 100% !important; - margin: 0 !important; - padding: 0 !important; -} - -/* Flyout submenu items — stretch to fill the popup width */ -.ots-sidebar.collapsed .sidebar-submenu .sidebar-list > a { - display: flex !important; - align-items: center !important; - justify-content: flex-start !important; - gap: 10px !important; - padding: 8px 16px !important; - margin: 2px 6px !important; - height: auto !important; - width: calc(100% - 12px) !important; - background: transparent !important; - color: var(--color-text-secondary, #f1f5f9) !important; - border-radius: 6px !important; - font-size: 13px !important; - white-space: nowrap !important; - border: none !important; - border-left: none !important; - text-decoration: none !important; - box-sizing: border-box !important; -} - -.ots-sidebar.collapsed .sidebar-submenu .sidebar-list > a:hover { - background: rgba(var(--ots-primary-rgb), 0.15) !important; - color: #ffffff !important; -} - -/* Show text labels inside flyout submenu — high specificity to override - the global .ots-sidebar.collapsed .ots-nav-text { display:none } */ -.ots-sidebar.collapsed .sidebar-submenu .sidebar-list .ots-nav-text, -.ots-sidebar.collapsed .sidebar-submenu .sidebar-list > a .ots-nav-text, -.ots-sidebar.collapsed .sidebar-submenu .ots-nav-text { - display: inline !important; - visibility: visible !important; - width: auto !important; - overflow: visible !important; - color: inherit !important; - font-size: 13px !important; - font-weight: 500 !important; -} - -/* Show icons inside flyout submenu — high specificity to override - collapsed icon sizing/color that makes them 20px sidebar icons */ -.ots-sidebar.collapsed .sidebar-submenu .sidebar-list .ots-nav-icon, -.ots-sidebar.collapsed .sidebar-submenu .sidebar-list > a .ots-nav-icon, -.ots-sidebar.collapsed .sidebar-submenu .ots-nav-icon { - display: inline-flex !important; - visibility: visible !important; - width: 18px !important; - height: 18px !important; - font-size: 14px !important; - flex-shrink: 0 !important; - color: inherit !important; - margin: 0 !important; - align-items: center !important; - justify-content: center !important; -} - -/* Make sidebar-group position relative so flyout anchors correctly */ -.ots-sidebar.collapsed .sidebar-group { - position: relative !important; -} - -/* Add a bridge element so the mouse can travel from the icon to the flyout - without losing :hover (covers the 4px gap + some tolerance) */ -.ots-sidebar.collapsed .sidebar-group-toggle::before { - content: '' !important; - position: absolute !important; - top: 0 !important; - right: -12px !important; - width: 12px !important; - height: 100% !important; - background: transparent !important; - display: block !important; - pointer-events: auto !important; - z-index: 9999 !important; -} - -/* Also show a label tooltip on hover for top-level items */ -.ots-sidebar.collapsed .sidebar-group-toggle::after { - content: attr(data-group); - position: absolute; - left: 100%; - top: 50%; - transform: translateY(-50%); - background: var(--color-surface-elevated, #334155); - color: var(--color-text-primary, #fff); - padding: 4px 12px; - border-radius: 6px; - font-size: 13px; - font-weight: 500; - white-space: nowrap; - margin-left: 8px; - pointer-events: none; - opacity: 0; - transition: opacity 0.15s; - z-index: 9999; - box-shadow: 0 4px 12px rgba(0,0,0,0.2); -} - -.ots-sidebar.collapsed .sidebar-group:hover > .sidebar-group-toggle::after { - display: none; /* hide tooltip when submenu flyout is showing instead */ -} - -/* Single items (Dashboard etc) - show tooltip on hover */ -.ots-sidebar.collapsed > .sidebar-content .sidebar-nav > .sidebar-list > a { - position: relative !important; -} - -.ots-sidebar.collapsed > .sidebar-content .sidebar-nav > .sidebar-list > a::after { - content: attr(data-tooltip); - position: absolute; - left: 100%; - top: 50%; - transform: translateY(-50%); - background: var(--color-surface-elevated, #334155); - color: var(--color-text-primary, #fff); - padding: 4px 12px; - border-radius: 6px; - font-size: 13px; - font-weight: 500; - white-space: nowrap; - margin-left: 8px; - pointer-events: none; - opacity: 0; - transition: opacity 0.15s; - z-index: 9999; - box-shadow: 0 4px 12px rgba(0,0,0,0.2); -} - -.ots-sidebar.collapsed > .sidebar-content .sidebar-nav > .sidebar-list:hover > a::after { - opacity: 1; -} - -.ots-sidebar.collapsed .sidebar-header { - height: auto; - padding: 8px; - justify-content: center; - flex-direction: column; - gap: 8px; -} - -.ots-sidebar.collapsed .brand-icon { - flex-shrink: 0; -} - -/* ── Collapsed sidebar: reset base Xibo styles and center icons ───────── */ - -/* The