/* ============================================================================ XIBO CMS MODERN THEME - OTS Signs Dark Mode Override - Component Styling ============================================================================ */ /* Force dark mode */ :root { --color-primary: #3b82f6; --color-primary-dark: #1d4ed8; --color-primary-light: #60a5fa; --color-primary-lighter: #dbeafe; --color-secondary: #7c3aed; --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; color-scheme: dark; } /* Ensure the page title/description remain visible when the sidebar is collapsed */ html.ots-sidebar-collapsed .page-header, body.ots-sidebar-collapsed .page-header, .ots-sidebar.collapsed ~ .ots-main .page-header, .ots-main .page-header { display: block !important; visibility: visible !important; height: auto !important; padding-top: 16px !important; padding-bottom: 16px !important; } html.ots-sidebar-collapsed .page-header h1, body.ots-sidebar-collapsed .page-header h1, .ots-sidebar.collapsed ~ .ots-main .page-header h1, .ots-main .page-header h1 { color: var(--color-text-primary) !important; } html.ots-sidebar-collapsed .page-header p.text-muted, body.ots-sidebar-collapsed .page-header p.text-muted, .ots-sidebar.collapsed ~ .ots-main .page-header p.text-muted, .ots-main .page-header p.text-muted { color: var(--color-text-tertiary) !important; } /* Ensure page header is not obscured by panels when sidebar is collapsed */ .ots-main .page-header { position: relative !important; z-index: 2500 !important; margin-top: 8px !important; margin-bottom: 12px !important; } /* Prevent immediate container clipping near the top */ .ots-content, .ots-main, .page-content { overflow: visible !important; } /* Fixed-position fallback: keep the page header visible and readable when sidebar is collapsed */ @media (min-width: 992px) { html.ots-sidebar-collapsed .page-header, body.ots-sidebar-collapsed .page-header, .ots-sidebar.collapsed ~ .ots-main .page-header { position: fixed !important; top: 16px !important; left: calc(var(--ots-sidebar-width,64px) + 24px) !important; /* fallback positions in case the CSS variable isn't set early */ left: 80px !important; left: 260px !important; right: 24px !important; z-index: 3200 !important; background: transparent !important; padding-top: 8px !important; padding-bottom: 8px !important; margin: 0 !important; } /* If sidebar is collapsed, prefer a smaller left offset */ html.ots-sidebar-collapsed .page-header, body.ots-sidebar-collapsed .page-header { left: 80px !important; } html.ots-sidebar-collapsed .page-header .ots-filter-header, body.ots-sidebar-collapsed .page-header .ots-filter-header { margin-top: 0 !important; } } html, body { background-color: var(--color-background); color: var(--color-text-primary); } /* ============================================================================ SHELL LAYOUT - SIDEBAR + MAIN ============================================================================ */ .ots-shell { display: flex; min-height: 100vh; } .ots-sidebar { position: fixed; left: 0; top: 0; width: 260px; height: 100vh; background-color: #08132a; border-right: 1px solid rgba(255, 255, 255, 0.06); padding: 0; display: flex; flex-direction: column; overflow-y: auto; z-index: 1000; } .ots-main { flex: 1; display: flex; flex-direction: column; margin-left: 260px; } .ots-content { flex: 1; padding: 32px; overflow-y: auto; } .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; } .ots-content { color: var(--color-text-primary); } } /* ============================================================================ SIDEBAR STYLES ============================================================================ */ .sidebar-header { padding: 20px 16px; border-bottom: 1px solid var(--color-border); display: flex; align-items: center; justify-content: space-between; gap: 12px; } .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: 32px; height: 32px; display: flex; align-items: center; justify-content: center; font-size: 24px; flex-shrink: 0; } .sidebar-content { flex: 1; padding: 12px 0; overflow-y: auto; } .sidebar-nav { list-style: none; margin: 0; padding: 72px 0 120px; } /* Extra top padding when sidebar is collapsed or expanded so items clear header */ .ots-sidebar.collapsed .sidebar-nav, .ots-sidebar-collapsed .sidebar-nav, .ots-sidebar:not(.collapsed) .sidebar-nav, .ots-sidebar-collapsed:not(.collapsed) .sidebar-nav { padding-top: 72px !important; } .sidebar-nav li { display: block; } /* 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: grid; grid-template-columns: 20px 1fr; align-items: center; column-gap: 12px; padding: 6px 10px; color: #c8d5ee; text-decoration: none; transition: all var(--transition-fast); position: relative; font-size: 14px; font-weight: 500; border-left: 2px solid transparent; margin: 3px 10px; border-radius: 12px; min-height: 40px; line-height: 1.25; } .ots-sidebar li.sidebar-list > a:hover { color: #ffffff; background-color: rgba(255, 255, 255, 0.08); } .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: #0b1221; background-color: #ffffff; border-left-color: transparent; font-weight: 600; box-shadow: 0 8px 18px rgba(15, 23, 42, 0.25); } .ots-sidebar .ots-nav-icon { width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 16px; color: currentColor; justify-self: center; } .ots-sidebar .ots-nav-text { font-size: 14px; font-weight: 500; flex: 1; line-height: 1.2; } .ots-sidebar li.sidebar-title > a { display: block; font-size: 10px; font-weight: 700; text-transform: uppercase; color: #8ea4c7; letter-spacing: 0.12em; padding: 12px 14px 4px; margin: 8px 0 0; min-height: auto; line-height: 1; } .nav-section-divider { padding: 12px 16px 8px; margin-top: 8px; border-top: 1px solid var(--color-border); } .nav-label { display: block; font-size: 11px; font-weight: 700; text-transform: uppercase; color: var(--color-text-tertiary); letter-spacing: 0.08em; padding: 12px 16px 8px; margin-top: 8px; } .nav-item { display: flex; align-items: center; gap: 14px; padding: 12px 16px; color: var(--color-text-primary); text-decoration: none; transition: all var(--transition-fast); position: relative; font-size: 14px; font-weight: 500; border-left: 2px solid transparent; margin: 0 4px; border-radius: 6px; } .nav-item:hover { color: var(--color-text-primary); background-color: rgba(59, 130, 246, 0.1); border-left-color: transparent; } .nav-item.active { color: var(--color-primary); background-color: rgba(59, 130, 246, 0.12); border-left-color: var(--color-primary); font-weight: 600; } .nav-item.active::after { content: ''; position: absolute; right: 8px; width: 8px; height: 8px; background-color: var(--color-primary); border-radius: 50%; } .nav-icon { width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 18px; } .nav-text { font-size: 14px; font-weight: 500; flex: 1; } .sidebar-footer { border-top: 1px solid var(--color-border); padding: 16px; background-color: rgba(59, 130, 246, 0.05); } .sidebar-user { display: flex; align-items: center; gap: 12px; } .user-avatar-lg { width: 40px; height: 40px; border-radius: 50%; background: linear-gradient(135deg, #3b82f6, #7c3aed); color: white; display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 16px; flex-shrink: 0; } .user-details { min-width: 0; } .user-name { font-size: 14px; font-weight: 600; color: var(--color-text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .user-role { color: var(--color-text-secondary); white-space: nowrap; } /* ============================================================================ TOPBAR STYLES - DEEP ANALYSIS & MODERN OVERHAUL ============================================================================ Design decisions: - 64px total height (44px content + 10px top/bottom padding) = consistent baseline - All interactive elements are 40px (buttons, search height) - Icon sizing: 20px container, 16px icon (scale-friendly) - Consistent 16px gap spacing throughout - Remove conflicting .navbar-nav rules - Proper z-index layering for dropdowns ============================================================================ */ .ots-topbar { background-color: var(--color-surface-elevated); border-bottom: 2px solid var(--color-border); padding: 8px 24px; display: flex; align-items: center; justify-content: flex-start; gap: 8px; height: 64px; z-index: 1100; position: sticky; top: 0; width: 100%; } /* Topbar nav container - override .navbar-nav defaults */ .ots-topbar.navbar-nav { background: transparent !important; border: 0 !important; padding: 0 !important; margin: 0 !important; gap: 6px; height: 100%; align-items: center; justify-content: flex-start; } .ots-topbar .nav-item { display: flex; align-items: center; height: 100%; margin: 0 !important; padding: 0 !important; } /* Brand stacking for 'OTS Signs' */ .xibo-logo-container { display: flex; align-items: center; gap: 12px; } .xibo-logo-text { display: inline-flex; flex-direction: column; line-height: 1; } .brand-line { display: block; margin: 0; padding: 0; } .brand-line-top { font-weight: 700; font-size: 18px; letter-spacing: 0.01em; } .brand-line-bottom { font-weight: 600; font-size: 13px; opacity: 0.95; margin-top: -2px; } .ots-topbar .nav-link { display: inline-flex; align-items: center; height: 100%; gap: 6px; padding: 0 8px; border-radius: 6px; color: var(--color-text-secondary); font-weight: 500; font-size: 14px; white-space: nowrap; transition: all var(--transition-fast); position: relative; } .ots-topbar .nav-link:hover { background-color: rgba(59, 130, 246, 0.08); color: var(--color-primary); } /* Ensure content is offset below the sticky topbar when horizontal nav present */ nav.navbar + #content-wrapper, nav.navbar + #content-wrapper .page-content { padding-top: 64px; } /* Right-side controls: notification bell + account menu */ .navbar-collapse .navbar-nav.navbar-right { margin-left: auto; display: flex; align-items: center; gap: 8px; } .navbar-collapse .navbar-nav.navbar-right > li { display: flex; align-items: center; } .header-side .user, .header-side .user-notif, .header-side .user-actions { display: inline-flex; align-items: center; gap: 8px; margin: 0; } .header-side .user-actions { float: right; display: flex; align-items: center; gap: 12px; } .header-side .user-actions > * { display: inline-flex !important; align-items: center; margin: 0 !important; padding: 0 !important; } .header-side .user-actions li, .header-side .user-actions .nav-item, .header-side .user-actions .dropdown, .header-side .user-actions .item, .header-side .user-actions .nav-link { display: inline-flex !important; align-items: center; width: auto !important; } .header-side .user-actions img.nav-avatar { display: block; width: 36px; height: 36px; } .header-side .user-actions .dropdown-menu { right: 0; left: auto; } /* Ensure header area does not clip absolutely positioned dropdowns */ .row.header.header-side, .row.header.header-side .col-sm-12, .row.header.header-side .user-actions { overflow: visible !important; } /* Ensure user dropdown renders above other content */ .header-side .user-actions .dropdown-menu, .ots-user-menu { z-index: 3000 !important; } /* When JS decides to open to the left (avoid viewport overflow) */ .dropdown-menu-left { left: auto !important; right: 0 !important; } /* When JS wants explicit left-aligned menu (menu's left edge aligned to trigger's left) */ .dropdown-menu-left-align { left: 0 !important; right: auto !important; } /* Force header row into a flex container so right-side controls align horizontally */ .row.header.header-side { position: relative; z-index: 10; } .row.header.header-side .col-sm-12 { display: flex !important; align-items: center !important; justify-content: flex-start !important; gap: 12px; } /* Ensure notification and user li elements render inline in header */ .header-side li.dropdown.nav-item.item, .header-side .dropdown.nav-item.item, .header-side .user-actions > li, .header-side .user-actions > .dropdown, .header-side .user-actions > .nav-item { display: inline-flex !important; float: none !important; vertical-align: middle !important; margin: 0 8px !important; } .header-side .nav-link { display: inline-flex !important; align-items: center !important; padding: 4px !important; } .header-side .ots-topbar-icon, .header-side .nav-avatar, .header-side img.nav-avatar { display: inline-block !important; vertical-align: middle !important; } /* Push user actions to the right and maintain flex layout */ .row.header.header-side .meta { flex: 0 0 auto; } .row.header.header-side .user-actions { margin-left: auto; display: flex !important; align-items: center !important; gap: 12px !important; flex-shrink: 0; } /* Ensure sidebar items are visible and above header when sidebar is collapsed */ .ots-sidebar.collapsed { z-index: 20; } .ots-sidebar.collapsed .ots-nav-icon { position: relative; z-index: 100; } @media (max-width: 991px) { /* When collapsed on small screens, allow the right nav to flow normally */ .navbar-collapse .navbar-nav.navbar-right { margin-left: 0; } } .ots-topbar .nav-item.open .nav-link, .ots-topbar .nav-item.active .nav-link { background-color: rgba(59, 130, 246, 0.12); color: var(--color-primary); font-weight: 600; } .ots-topbar .dropdown-toggle::after { content: ''; display: inline-block; margin-left: 6px; width: 0; height: 0; border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 4px solid currentColor; opacity: 0.6; transition: transform var(--transition-fast); } .ots-topbar .nav-item.open .dropdown-toggle::after { transform: rotate(180deg); } .ots-topbar .dropdown-menu { border-radius: 8px; padding: 6px 0; margin-top: 4px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); border: 1px solid var(--color-border); background-color: var(--color-surface); min-width: 180px; z-index: 1100; } .ots-topbar .dropdown-item, .ots-topbar .dropdown-menu a { display: flex; align-items: center; gap: 8px; border-radius: 4px; padding: 8px 14px; color: var(--color-text-secondary); font-size: 14px; font-weight: 500; margin: 2px 6px; transition: all var(--transition-fast); } .ots-topbar .dropdown-item:hover, .ots-topbar .dropdown-menu a:hover { background-color: rgba(59, 130, 246, 0.1); color: var(--color-primary); } /* Icon sizing for topbar and nav */ .ots-topbar-icon { width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; font-size: 14px; opacity: 0.9; flex-shrink: 0; } .ots-topbar .dropdown-menu .ots-topbar-icon { font-size: 13px; } /* Left section: toggle, title, nav */ .topbar-left { display: flex; align-items: center; gap: 16px; flex: 1; min-width: 0; } .topbar-toggle { display: none; width: 40px; height: 40px; padding: 0; border: none; background-color: transparent; color: var(--color-text-primary); cursor: pointer; border-radius: 6px; transition: all var(--transition-fast); flex-shrink: 0; } .topbar-toggle:hover { background-color: rgba(59, 130, 246, 0.1); } .topbar-toggle:active { background-color: rgba(59, 130, 246, 0.15); } .topbar-toggle .icon { width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; } /* Title section with proper vertical centering */ .topbar-title { display: flex; flex-direction: column; justify-content: center; gap: 0; min-width: 0; } .topbar-title h1 { margin: 0; padding: 0; font-size: 18px; font-weight: 700; color: var(--color-text-primary); line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .topbar-title p { margin: 0; padding: 0; font-size: 12px; color: var(--color-text-tertiary); line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* Right section: search, actions */ .topbar-right { display: flex; align-items: center; gap: 12px; flex-shrink: 0; } /* Search box - 40px height to match button grid */ .topbar-search { position: relative; height: 40px; width: 280px; display: flex; align-items: center; background-color: var(--color-surface); border: 1px solid var(--color-border); border-radius: 6px; padding: 0 12px; gap: 8px; transition: all var(--transition-fast); } .topbar-search:focus-within { border-color: var(--color-primary); box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1); } .topbar-search .search-icon { color: var(--color-text-tertiary); flex-shrink: 0; font-size: 16px; width: 16px; height: 16px; display: flex; align-items: center; justify-content: center; } .topbar-search .search-input { flex: 1; background: none; border: none; color: var(--color-text-primary); font-size: 14px; outline: none; padding: 0; height: 100%; min-width: 120px; } .topbar-search .search-input::placeholder { color: var(--color-text-tertiary); } /* Action buttons container */ .topbar-actions { display: flex; align-items: center; gap: 4px; } /* Consistent 40px button sizing */ .topbar-btn { width: 40px; height: 40px; min-width: 40px; min-height: 40px; padding: 0; border: none; background-color: transparent; color: var(--color-text-secondary); cursor: pointer; border-radius: 6px; display: flex; align-items: center; justify-content: center; transition: all var(--transition-fast); position: relative; } .topbar-btn:hover { background-color: rgba(59, 130, 246, 0.08); color: var(--color-primary); } .topbar-btn:active { background-color: rgba(59, 130, 246, 0.12); } .topbar-btn .icon { width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; font-size: 16px; } .user-btn { padding: 2px; } .avatar { width: 36px; height: 36px; border-radius: 50%; background: linear-gradient(135deg, #3b82f6, #7c3aed); color: white; display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 14px; } .avatar-sm { width: 32px; height: 32px; font-size: 13px; } .dropdown { position: relative; } .dropdown-menu, .dropdown-right { position: absolute; top: 100%; right: 0; margin-top: 8px; background-color: var(--color-surface-elevated); border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 8px; box-shadow: 0 20px 45px rgba(0, 0, 0, 0.3); list-style: none; padding: 8px 0; min-width: 180px; display: none; z-index: 1001; overflow: hidden; } .dropdown.active .dropdown-menu, .dropdown:focus-within .dropdown-menu { display: block; animation: slideDown 150ms ease-out; } @keyframes slideDown { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: translateY(0); } } .dropdown-menu li { display: block; } /* OTS topbar badge removed */ .dropdown-menu li a { display: flex; align-items: center; gap: 12px; padding: 10px 16px; color: var(--color-text-primary); text-decoration: none; font-size: 14px; transition: all var(--transition-fast); font-weight: 500; } .dropdown-menu li a:hover { background-color: rgba(59, 130, 246, 0.1); color: var(--color-primary); } .dropdown-menu li a:active { background-color: rgba(59, 130, 246, 0.15); } /* ============================================================================ DASHBOARD PAGE ============================================================================ */ /* OTS dashboard message (theme-dashboard-message.twig) */ .ots-dashboard-message { margin: 16px 0 24px; padding: 12px 16px; border-radius: 10px; background: rgba(59, 130, 246, 0.12); border: 1px solid rgba(59, 130, 246, 0.35); color: var(--color-text-primary); } .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(--color-text-secondary); } .dashboard-page { display: flex; flex-direction: column; gap: 32px; } .page-header { margin-bottom: 16px; } /* When the sidebar is collapsed, hide the page header and meta area to provide a compact layout consistent with the collapsed navigation state. */ .ots-sidebar.collapsed ~ .ots-main .page .meta, .ots-sidebar.collapsed ~ .ots-main .page-header, .ots-sidebar.collapsed ~ .ots-main .header-side, .ots-sidebar.collapsed + .ots-main .page .meta, .ots-sidebar.collapsed + .ots-main .page-header, .ots-sidebar-collapsed .ots-main .page .meta, .ots-sidebar-collapsed .ots-main .page-header, body.ots-sidebar-collapsed .page .meta, body.ots-sidebar-collapsed .page-header { display: none !important; margin: 0 !important; padding: 0 !important; } .page-header h1 { margin: 0 0 8px; font-size: 32px; font-weight: 700; } .page-header .text-muted { margin: 0; font-size: 16px; color: var(--color-text-secondary); } /* KPI Section */ .kpi-section { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; } .kpi-card { background-color: var(--color-surface); border: 1px solid var(--color-border); border-radius: 8px; padding: 20px; transition: all var(--transition-base); } .kpi-card:hover { border-color: var(--color-primary); box-shadow: 0 0 0 1px var(--color-primary); } .kpi-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 16px; } .kpi-label { margin: 0; font-size: 14px; font-weight: 600; color: var(--color-text-secondary); text-transform: uppercase; letter-spacing: 0.05em; } .kpi-icon-box { width: 40px; height: 40px; border-radius: 6px; background: linear-gradient(135deg, rgba(59, 130, 246, 0.2), rgba(124, 58, 237, 0.2)); display: flex; align-items: center; justify-content: center; color: var(--color-primary); } .kpi-body { margin-bottom: 12px; } .kpi-number { font-size: 32px; font-weight: 700; color: var(--color-text-primary); line-height: 1; margin-bottom: 4px; } .kpi-meta { font-size: 13px; color: var(--color-text-secondary); } .kpi-footer { display: flex; align-items: center; gap: 8px; padding-top: 12px; border-top: 1px solid var(--color-border); } /* Badges */ .badge { display: inline-block; padding: 4px 10px; border-radius: 4px; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; } .badge-success { background-color: rgba(16, 185, 129, 0.2); color: #a7f3d0; } .badge-danger { background-color: rgba(239, 68, 68, 0.2); color: #fca5a5; } .badge-info { background-color: rgba(14, 165, 233, 0.2); color: #7dd3fc; } .badge-secondary { background-color: rgba(124, 58, 237, 0.2); color: #d8b4fe; } /* Dashboard Panels */ .dashboard-panels { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; } /* Dashboard chart cards (bandwidth/library) */ .dashboard-chart-card { background: linear-gradient(180deg, rgba(59, 130, 246, 0.06), rgba(59, 130, 246, 0.02)); border: 1px solid rgba(59, 130, 246, 0.18); box-shadow: 0 12px 26px rgba(8, 15, 30, 0.35); } .dashboard-chart-header { display: flex; justify-content: space-between; align-items: center; gap: 16px; } .dashboard-chart-title { display: flex; align-items: center; gap: 12px; } .dashboard-chart-icon { width: 40px; height: 40px; border-radius: 12px; background: rgba(59, 130, 246, 0.18); color: var(--color-primary-light); display: inline-flex; align-items: center; justify-content: center; font-size: 18px; flex-shrink: 0; } .dashboard-chart-heading { margin: 0; font-size: 16px; font-weight: 700; } .dashboard-chart-subtitle { margin: 4px 0 0; font-size: 12px; color: var(--color-text-secondary); } .dashboard-chart-link { font-size: 12px; font-weight: 600; color: var(--color-primary); text-decoration: none; padding: 6px 10px; border-radius: 999px; border: 1px solid rgba(59, 130, 246, 0.24); background: rgba(59, 130, 246, 0.12); transition: all var(--transition-fast); white-space: nowrap; } .dashboard-chart-link:hover { color: var(--color-text-primary); border-color: rgba(59, 130, 246, 0.5); background: rgba(59, 130, 246, 0.22); } .dashboard-chart-body { padding: 0 20px 20px; } .dashboard-chart-canvas { background: rgba(15, 23, 42, 0.45); border: 1px solid rgba(255, 255, 255, 0.05); border-radius: 12px; padding: 12px; height: 250px; position: relative; overflow: hidden; } .dashboard-chart-canvas canvas { display: block; width: 100% !important; height: 100% !important; max-width: 100% !important; max-height: 100% !important; margin: 0 !important; } .dashboard-chart-card .panel-body canvas, .dashboard-chart-card .widget-body canvas { min-height: 0 !important; } .panel { background-color: var(--color-surface); border: 1px solid var(--color-border); border-radius: 8px; overflow: hidden; display: flex; flex-direction: column; } /* Force Xibo panels/cards to dark theme (use higher specificity to override core styles) */ body .panel, body .panel.panel-default, .panel.panel-white, .panel.card, .panel.box, .widget { background-color: var(--color-surface) !important; color: var(--color-text-primary) !important; border: 1px solid var(--color-border) !important; } body .panel .panel-body, body .panel .panel-footer, body .panel .panel-heading, .panel .panel-header { background-color: transparent !important; color: var(--color-text-primary) !important; border-color: var(--color-border) !important; } body .panel .panel-heading, .panel .panel-header { background-color: var(--color-surface-elevated) !important; border-bottom: 1px solid var(--color-border) !important; } /* Tables inside panels should inherit dark background and readable text */ .panel table, .panel table thead, .panel table tbody, .panel table tr, .panel table td, .panel table th, .panel .dataTables_wrapper { background-color: transparent !important; color: var(--color-text-primary) !important; } /* Card-specific fallbacks */ .card, .card .card-body { background-color: var(--color-surface) !important; color: var(--color-text-primary) !important; border: 1px solid var(--color-border) !important; } .panel-full { grid-column: 1 / -1; } .panel-header { padding: 20px; border-bottom: 1px solid var(--color-border); display: flex; justify-content: space-between; align-items: center; } .panel-header h3 { margin: 0; font-size: 16px; font-weight: 600; color: var(--color-text-primary); } .link-secondary { color: var(--color-primary); text-decoration: none; font-size: 13px; font-weight: 500; transition: color var(--transition-fast); } .link-secondary:hover { color: var(--color-primary-light); } .panel-body { padding: 20px; flex: 1; display: flex; flex-direction: column; min-height: 0; } .empty-state-compact { text-align: center; padding: 20px 0; } .empty-state-compact p { margin: 0 0 16px; color: var(--color-text-secondary); } /* Quick Actions */ .quick-actions-grid { margin-top: 32px; } .section-title { margin: 0 0 16px; font-size: 18px; font-weight: 600; color: var(--color-text-primary); } .action-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; } .action-card { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; padding: 24px; background-color: var(--color-surface); border: 1px solid var(--color-border); border-radius: 8px; text-decoration: none; color: var(--color-text-primary); transition: all var(--transition-base); cursor: pointer; } .action-card:hover { border-color: var(--color-primary); background-color: rgba(59, 130, 246, 0.05); transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); } .action-icon { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; color: var(--color-primary); } .action-label { font-size: 14px; font-weight: 600; text-align: center; } /* ============================================================================ TWO-COLUMN LAYOUT (Displays, Media) ============================================================================ */ .ots-displays-page .page-header { margin-bottom: 20px; } .ots-displays-card { padding: 0; display: flex; flex-direction: column; min-width: 0; } .ots-displays-body { flex: 1; min-width: 0; display: flex; flex-direction: column; } .ots-displays-body .XiboGrid { flex: 1; min-width: 0; display: flex; flex-direction: column; } .ots-displays-title { font-size: 18px; font-weight: 700; letter-spacing: 0.02em; } /* Filter card - modern container */ .ots-filter-card { background: linear-gradient(135deg, rgba(15, 23, 42, 0.4), rgba(15, 23, 42, 0.2)); border: none; box-shadow: 0 4px 20px rgba(6, 10, 20, 0.15); margin-bottom: 0; border-radius: 16px; overflow: hidden; } /* Filter header with collapse button */ .ots-filter-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 16px; border: none; background: transparent; } .ots-filter-title { font-weight: 700; color: var(--color-text-primary); font-size: 14px; letter-spacing: 0.03em; text-transform: uppercase; margin: 0; } .ots-filter-toggle { width: 36px; height: 36px; padding: 0; border: none; background: rgba(59, 130, 246, 0.08); color: var(--color-text-secondary); cursor: pointer; display: flex; align-items: center; justify-content: center; border-radius: 10px; transition: all 200ms ease; } .ots-filter-toggle:hover { background: rgba(59, 130, 246, 0.16); color: var(--color-primary); } .ots-filter-content { padding: 0 16px 12px 16px; max-height: none; min-height: auto; overflow: visible; transition: max-height 300ms ease-out, padding 300ms ease-out; display: block; } .ots-filter-content.collapsed { max-height: 0; min-height: 0; padding: 0 16px; overflow: hidden; display: none; } /* When the whole filter card is collapsed, reduce to a small floating button positioned top-left so the page has minimal clutter but the user can reopen the filter. This keeps the header and toggle usable. */ .ots-filter-card.collapsed { position: fixed !important; top: 12px !important; left: 12px !important; width: 48px !important; height: 48px !important; border-radius: 10px !important; padding: 6px !important; background: var(--color-surface, #ffffff) !important; box-shadow: 0 6px 20px rgba(6,10,20,0.18) !important; z-index: 1400 !important; overflow: visible !important; } .ots-filter-card.collapsed .ots-filter-header { display: flex !important; align-items: center !important; justify-content: center !important; padding: 0 !important; height: 100% !important; } .ots-filter-card.collapsed .ots-filter-title { display: none !important; } .ots-filter-card.collapsed .ots-filter-toggle { width: 36px !important; height: 36px !important; border-radius: 8px !important; background: transparent !important; } .ots-filter-card.collapsed .ots-filter-content { display: none !important; } .ots-filter-card .nav-tabs { display: none; } .ots-filter-card .tab-content { display: block; } .ots-filter-card .tab-pane { display: none; } .ots-filter-card .tab-pane.active, .ots-filter-card .tab-pane.show { display: block; } .ots-filter-card .form-inline { display: flex; flex-wrap: nowrap; gap: 12px; align-items: flex-end; overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch; padding-bottom: 4px; } .ots-filter-card .form-inline .form-group, .ots-filter-card .form-inline .input-group { margin-right: 0; margin-bottom: 0; flex: 0 0 auto; min-width: 180px; } .ots-filter-card .form-control, .ots-filter-card select, .ots-filter-card .select2-selection, .ots-filter-card .input-group-addon, .ots-filter-card .input-group-text { background-color: var(--color-surface) !important; background-image: none !important; border: 1px solid var(--color-border) !important; color: var(--color-text-primary) !important; border-radius: 10px !important; padding: 12px 14px !important; font-size: 15px !important; font-family: inherit !important; transition: border 150ms ease, box-shadow 150ms ease !important; height: 48px !important; line-height: 1.4 !important; box-shadow: none !important; box-sizing: border-box !important; } .ots-filter-card .input-group { display: flex; align-items: center; gap: 6px; } .ots-filter-card .input-group > .form-control, .ots-filter-card .input-group > .custom-select, .ots-filter-card .input-group > .select2-container { min-width: 0; flex: 1 1 auto; } .ots-filter-card .form-control:focus, .ots-filter-card select:focus, .ots-filter-card .select2-selection:focus { border-color: rgba(96, 165, 250, 0.7) !important; box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2), 0 10px 24px rgba(6, 10, 20, 0.25) !important; background: rgba(15, 23, 42, 0.9) !important; } .ots-filter-card label { color: var(--color-text-tertiary); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 2px; display: block; } .ots-filter-card .select2-selection__rendered { color: var(--color-text-primary) !important; line-height: 20px !important; } .ots-filter-card .select2-container--default .select2-selection--single, .ots-filter-card .select2-container--default .select2-selection--multiple { background-color: var(--color-surface) !important; background-image: none !important; border: 1px solid var(--color-border) !important; border-radius: 10px !important; min-height: 44px !important; box-shadow: none !important; } .ots-filter-card .select2-container--default .select2-selection--multiple .select2-search__field { color: var(--color-text-primary) !important; background: transparent !important; } .ots-filter-card .select2-container--default .select2-selection--multiple .select2-selection__choice { background: rgba(59, 130, 246, 0.2) !important; border: 1px solid rgba(59, 130, 246, 0.4) !important; color: var(--color-text-primary) !important; border-radius: 999px !important; } .ots-filter-card .bootstrap-tagsinput, .ots-filter-card .tagsinput { background-color: var(--color-surface) !important; background-image: none !important; border: 1px solid var(--color-border) !important; border-radius: 10px !important; color: var(--color-text-primary) !important; min-height: 44px !important; padding: 6px 10px !important; box-shadow: none !important; } .ots-filter-card .bootstrap-tagsinput input, .ots-filter-card .tagsinput input { background: transparent !important; color: var(--color-text-primary) !important; } .ots-filter-card .select2-selection__arrow b { border-color: var(--color-text-secondary) transparent transparent transparent !important; } .ots-filter-card .input-group { background: transparent; } .ots-filter-card .input-group .form-control { border-top-right-radius: 0 !important; border-bottom-right-radius: 0 !important; } .ots-filter-card .input-group-append .input-group-text, .ots-filter-card .input-group-addon { border-top-left-radius: 0 !important; border-bottom-left-radius: 0 !important; font-weight: 600; height: 44px !important; display: inline-flex !important; align-items: center !important; justify-content: center !important; padding: 0 12px !important; } .ots-filter-card .input-group .input-group-prepend .input-group-text, .ots-filter-card .input-group .input-group-append .input-group-text { border-radius: 10px !important; } .ots-filter-card .input-group .btn, .ots-filter-card .input-group .btn.btn-secondary { height: 44px; padding: 0 14px; border-radius: 999px; border: 1px solid rgba(148, 163, 184, 0.25); background: rgba(30, 41, 59, 0.55); color: var(--color-text-primary); font-weight: 600; letter-spacing: 0.02em; } .ots-filter-card input::placeholder, .ots-filter-card textarea::placeholder { color: rgba(148, 163, 184, 0.7) !important; } .ots-filter-card select { appearance: none; -webkit-appearance: none; -moz-appearance: none; background-image: linear-gradient(45deg, transparent 50%, rgba(148, 163, 184, 0.7) 50%), linear-gradient(135deg, rgba(148, 163, 184, 0.7) 50%, transparent 50%); background-position: calc(100% - 16px) 17px, calc(100% - 12px) 17px; background-size: 4px 4px, 4px 4px; background-repeat: no-repeat; padding-right: 28px !important; } .ots-filter-card .form-check-input { width: 18px; height: 18px; border-radius: 6px; border: 1px solid rgba(148, 163, 184, 0.35); background: rgba(15, 23, 42, 0.65); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.02); } .ots-filter-card .form-check-input:checked { background: var(--color-primary); border-color: rgba(96, 165, 250, 0.8); } .ots-grid-with-folders { display: grid; grid-template-columns: 260px 1fr; gap: 32px; align-items: start; width: 100%; transition: grid-template-columns 200ms ease-out; } .ots-grid-with-folders.ots-folder-collapsed { grid-template-columns: 1fr; gap: 0; } .ots-grid-with-folders.ots-folder-collapsed .ots-folder-tree { display: none; width: 0; overflow: hidden; } .ots-folder-tree { min-height: 320px; padding: 16px; margin-right: -8px; max-width: 100%; box-sizing: content-box; } .ots-folder-tree .form-check { margin-top: 12px; } .ots-grid-controller { margin-top: 8px; } .ots-grid-controller .btn { border-radius: 10px; box-shadow: 0 6px 16px rgba(8, 15, 30, 0.25); } .ots-table-card { padding: 12px 16px 16px; flex: 1; min-width: 0; overflow: hidden; } #datatable-container { width: 100%; overflow-x: auto; } .ots-table-card .table thead th { background: rgba(15, 23, 42, 0.9); color: var(--color-text-primary); border-bottom: 1px solid rgba(148, 163, 184, 0.2); } .ots-table-card .table thead th, .ots-table-card .table tbody td, .ots-table-card .table tbody th, .ots-table-card .table tbody tr { color: #e2e8f0; } .ots-table-card .table tbody tr { background: rgba(15, 23, 42, 0.7); } .ots-table-card .table tbody tr:nth-child(even) { background: rgba(30, 41, 59, 0.75); } .ots-table-card .table tbody tr:hover { background: rgba(59, 130, 246, 0.14); color: #ffffff; } .ots-table-card .table tbody tr.selected, .ots-table-card .table tbody tr.dt-row-selected, .ots-table-card .table tbody tr.selected td, .ots-table-card .table tbody tr.dt-row-selected td { background: rgba(16, 185, 129, 0.25) !important; color: #ffffff !important; } .ots-table-card .dataTables_wrapper, .ots-table-card .dataTables_wrapper * { color: #e2e8f0 !important; } .ots-table-card .dataTables_wrapper .dataTables_filter input, .ots-table-card .dataTables_wrapper .dataTables_length select { background: rgba(15, 23, 42, 0.8) !important; color: #e2e8f0 !important; border: 1px solid rgba(148, 163, 184, 0.25) !important; } /* Extra specificity for Xibo Displays DataTable */ .ots-displays-page #datatable-container .XiboData .table, .ots-displays-page #datatable-container .XiboData table.dataTable { color: #e2e8f0 !important; } .ots-displays-page #datatable-container .XiboData .table thead th, .ots-displays-page #datatable-container .XiboData table.dataTable thead th { color: #cbd5e1 !important; background-color: var(--color-surface) !important; font-weight: 600 !important; opacity: 1 !important; } .ots-displays-page #datatable-container .XiboData .table tbody td, .ots-displays-page #datatable-container .XiboData table.dataTable tbody td { color: #e2e8f0 !important; opacity: 1 !important; } .ots-displays-page #datatable-container .XiboData table.dataTable tbody tr { background-color: rgba(15, 23, 42, 0.75) !important; } /* Status icons in Displays table */ .ots-displays-page #datatable-container .fa-check, .ots-displays-page #datatable-container .fa-check-circle { color: var(--color-success) !important; } .ots-displays-page #datatable-container .fa-times, .ots-displays-page #datatable-container .fa-times-circle, .ots-displays-page #datatable-container .fa-x { color: var(--color-danger) !important; } .ots-displays-page #datatable-container .XiboData table.dataTable tbody tr:nth-child(even) { background-color: rgba(30, 41, 59, 0.8) !important; } .ots-table-card .table tbody tr:hover { background: rgba(59, 130, 246, 0.08); } .ots-map-card { margin-top: 16px; min-height: 360px; background: rgba(15, 23, 42, 0.6); border: 1px solid rgba(148, 163, 184, 0.2); border-radius: 16px; } @media (max-width: 1024px) { .ots-grid-with-folders { grid-template-columns: 1fr; } } .two-column-layout { display: grid; grid-template-columns: 280px 1fr; gap: 24px; height: calc(100vh - 130px); } .left-panel { background-color: var(--color-surface); border: 1px solid var(--color-border); border-radius: 8px; display: flex; flex-direction: column; overflow-y: auto; } .content-panel { display: flex; flex-direction: column; gap: 16px; } .folder-tree { padding: 8px 0; } .folder-item { display: flex; align-items: center; gap: 12px; padding: 10px 16px; color: var(--color-text-secondary); cursor: pointer; transition: all var(--transition-fast); } .folder-item:hover { background-color: var(--color-surface-elevated); color: var(--color-text-primary); } .folder-item.active { background-color: rgba(59, 130, 246, 0.15); color: var(--color-primary); } .folder-icon { width: 18px; height: 18px; flex-shrink: 0; } .folder-name { font-size: 14px; font-weight: 500; } .content-toolbar { display: flex; align-items: center; gap: 16px; padding: 16px; background-color: var(--color-surface); border: 1px solid var(--color-border); border-radius: 8px; } .search-wrapper { flex: 1; position: relative; display: flex; align-items: center; background-color: var(--color-surface-elevated); border: 1px solid var(--color-border); border-radius: 6px; padding: 8px 12px; } .search-icon { color: var(--color-text-tertiary); margin-right: 8px; flex-shrink: 0; } .search-field { flex: 1; background: none; border: none; color: var(--color-text-primary); font-size: 14px; outline: none; padding: 0; } .search-field::placeholder { color: var(--color-text-tertiary); } .toolbar-actions { display: flex; align-items: center; gap: 12px; } .stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 12px; } .stat-box { background-color: var(--color-surface); border: 1px solid var(--color-border); border-radius: 6px; padding: 12px; text-align: center; } .stat-label { font-size: 12px; color: var(--color-text-secondary); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 8px; } .stat-value { font-size: 24px; font-weight: 700; color: var(--color-text-primary); } .text-success { color: #10b981; } .text-danger { color: #ef4444; } /* ============================================================================ TABLES ============================================================================ */ .table-wrapper { background-color: var(--color-surface); border: 1px solid var(--color-border); border-radius: 8px; overflow-x: auto; } .table { width: 100%; border-collapse: collapse; margin: 0; font-size: 14px; } .table thead { background-color: var(--color-surface); border-bottom: 2px solid var(--color-border); } .table thead th { padding: 12px 16px; text-align: left; font-weight: 600; color: var(--color-text-secondary); text-transform: uppercase; letter-spacing: 0.05em; font-size: 11px; background-color: var(--color-surface); } /* Status icons and checkmarks color */ .table tbody td .fa-check, .table tbody td .fa-check-circle { color: var(--color-success); } .table tbody td .fa-times, .table tbody td .fa-times-circle, .table tbody td .fa-x { color: var(--color-danger); } .table tbody td .fa-exclamation, .table tbody td .fa-exclamation-circle, .table tbody td .fa-question-circle { color: var(--color-warning); } .table tbody td .fa-info-circle { color: var(--color-info); } .table tbody tr { border-bottom: 1px solid var(--color-border); transition: background-color var(--transition-fast); } .table tbody tr:hover { background-color: var(--color-surface-elevated); } .table tbody td { padding: 12px 16px; color: var(--color-text-primary); } .table-striped tbody tr:nth-child(even) { background-color: rgba(59, 130, 246, 0.02); } /* ============================================================================ MEDIA LIBRARY ============================================================================ */ .media-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px; padding: 16px; background-color: var(--color-surface); border: 1px solid var(--color-border); border-radius: 8px; } .media-item { background-color: var(--color-surface-elevated); border: 1px solid var(--color-border); border-radius: 6px; overflow: hidden; cursor: pointer; transition: all var(--transition-base); } .media-item:hover { border-color: var(--color-primary); box-shadow: 0 4px 12px rgba(59, 130, 246, 0.2); transform: translateY(-4px); } .media-thumbnail { position: relative; width: 100%; padding-bottom: 75%; overflow: hidden; background-color: var(--color-border); } .media-thumbnail img { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; } .media-type-badge { position: absolute; top: 8px; right: 8px; background-color: rgba(0, 0, 0, 0.6); color: white; padding: 4px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; text-transform: uppercase; } .media-info { padding: 12px; } .media-name { margin: 0 0 4px; font-size: 14px; font-weight: 600; color: var(--color-text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .media-size { margin: 0; color: var(--color-text-tertiary); } /* ============================================================================ BUTTONS ============================================================================ */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; padding: 10px 16px; border: none; border-radius: 6px; font-size: 14px; font-weight: 600; text-decoration: none; cursor: pointer; transition: all var(--transition-fast); white-space: nowrap; } .btn-primary { background-color: var(--color-primary); color: white; } .btn-primary:hover { background-color: var(--color-primary-dark); } .btn-outline { background-color: transparent; border: 1px solid var(--color-border); color: var(--color-text-primary); } .btn-outline:hover { background-color: var(--color-surface); border-color: var(--color-primary); color: var(--color-primary); } .btn-sm { padding: 6px 12px; font-size: 13px; } .btn-ghost { background-color: transparent; color: var(--color-text-secondary); padding: 0; } .btn-ghost:hover { color: var(--color-text-primary); } /* ============================================================================ UTILITY CLASSES ============================================================================ */ .text-muted { color: var(--color-text-secondary); } .text-tertiary { color: var(--color-text-tertiary); } .text-xs { font-size: 12px; } .text-sm { font-size: 14px; } .form-control { background-color: var(--color-surface); border: 1px solid var(--color-border); color: var(--color-text-primary); padding: 8px 12px; border-radius: 6px; font-size: 14px; } .form-control::placeholder { color: var(--color-text-secondary); } .form-control:focus { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); } /* ============================================================================ RESPONSIVE ============================================================================ */ @media (max-width: 768px) { .ots-topbar { flex-direction: column; align-items: flex-start; gap: 12px; height: auto; padding: 12px 16px; } .topbar-right { width: 100%; flex-direction: column; } .topbar-search { width: 100%; } .two-column-layout { grid-template-columns: 1fr; height: auto; } .left-panel { max-height: 300px; } .dashboard-panels { grid-template-columns: 1fr; } .kpi-section { grid-template-columns: 1fr; } .action-cards { grid-template-columns: 1fr; } .media-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); } .ots-content { padding: 16px; } .ots-footer { padding: 12px 16px; } } /* ============================================================================ CANVAS / CHART ELEMENTS ============================================================================ */ /* Ensure canvas elements and chart containers render properly */ canvas { max-width: 100%; height: auto; display: block; } .chart-container, .chart-wrapper, [class*="chart"] { position: relative; width: 100%; height: 100%; } /* OTS sidebar override marker */ .ots-sidebar-wrapper { box-shadow: inset 0 0 0 1px rgba(59, 130, 246, 0.15); } .ots-sidebar .sidebar-list a, .ots-sidebar .sidebar-main a { display: flex; align-items: center; gap: 10px; } .ots-nav-icon { width: 18px; text-align: center; opacity: 0.85; font-size: 14px; } .ots-nav-text { flex: 1; min-width: 0; } /* Xibo sidebar refinements (light) */ #sidebar-wrapper .sidebar-title a { color: var(--color-text-tertiary); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; padding: 12px 16px 6px; } #sidebar-wrapper .sidebar-list a, #sidebar-wrapper .sidebar-main a { display: block; margin: 2px 8px; padding: 10px 12px; border-radius: 8px; transition: background-color var(--transition-fast), color var(--transition-fast); } #sidebar-wrapper .sidebar-list a:hover, #sidebar-wrapper .sidebar-main a:hover { background: rgba(59, 130, 246, 0.1); color: var(--color-primary); } /* Ensure chart parent containers have proper sizing */ .panel-body canvas, .panel-body .chart-container { flex: 1; min-height: 300px; } .panel-body > div[class*="chart"], .panel-body > div > canvas { width: 100% !important; height: 100% !important; } /* Hidden dashboard chart canvas bridge */ .chart-sandbox { position: absolute; left: -10000px; top: -10000px; width: 1px; height: 1px; overflow: hidden; pointer-events: none; } .chart-sandbox canvas { width: 1px !important; height: 1px !important; } /* Transition variable fallback */ :root { --transition-fast: 150ms ease-in-out; --transition-base: 200ms ease-in-out; --transition-slow: 300ms ease-in-out; } /* ================================================================ Modern table styles (theme override) Applied: makes XIBO tables look cleaner and responsive ================================================================ */ .modern-table-card { background: linear-gradient(180deg, rgba(255,255,255,0.02), rgba(255,255,255,0.01)); border-radius: 10px; box-shadow: 0 6px 18px rgba(2,6,23,0.45); padding: 18px; margin: 16px 0; border: 1px solid rgba(255,255,255,0.02); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial; } .modern-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 13px; color: var(--color-text-primary); } .modern-table thead th { background: linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.03)); color: var(--color-text-primary); font-weight: 700; text-transform: uppercase; letter-spacing: .06em; font-size: 11px; padding: 10px 12px; border-bottom: 1px solid rgba(255,255,255,0.1); position: sticky; top: 0; z-index: 2; } .modern-table tbody tr { background: transparent; } .modern-table tbody tr:nth-child(odd) { background: rgba(255,255,255,0.01); } .modern-table tbody tr:hover { background: rgba(59,130,246,0.06); } .modern-table td { padding: 12px; vertical-align: middle; border-bottom: 1px solid rgba(255,255,255,0.02); } .table-controls { display:flex; gap:8px; align-items:center; justify-content:flex-end; margin-bottom:12px; } .table-controls .btn { background: var(--color-primary); color: var(--color-on-primary); border-radius: 999px; padding: 6px 10px; font-size: 13px; border: none; cursor: pointer; } .table-controls .btn.ghost { background:transparent; color:var(--color-primary); border:1px solid rgba(59,130,246,0.12); } .table-meta { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding-top: 10px; font-size: 13px; color: var(--color-text-secondary); } @media (max-width: 880px) { .modern-table thead th:nth-child(n+6), .modern-table tbody td:nth-child(n+6) { display: none; } .modern-table tbody td.details-toggle { display: table-cell; } .modern-table-card { padding: 12px; } } /* Improve legibility: force table and datatables text to full contrast */ .modern-table, .modern-table tbody, .modern-table tbody tr, .modern-table td, .dataTables_wrapper, .dataTables_wrapper table, .dataTables_wrapper .dataTables_info, .dataTables_wrapper .dataTables_length, .dataTables_wrapper .dataTables_filter { color: var(--Color-fallback, var(--color-text-primary)) !important; opacity: 1 !important; } /* Stronger selected row for readability */ .modern-table tbody tr.selected, .modern-table tbody tr.dt-row-selected, .dataTables_wrapper table tbody tr.selected, .dataTable tbody tr.selected { background: rgba(16,185,129,0.14) !important; /* stronger mint */ color: var(--color-text-primary) !important; } /* Inputs and selects used in filters/search should be readable */ .dataTables_wrapper .dataTables_filter input, .dataTables_wrapper .dataTables_length select, .topbar-search .search-input, .table-controls input, input[type="search"], input[type="text"], select, textarea { background: var(--color-surface) !important; color: var(--color-text-primary) !important; border: 1px solid var(--color-border) !important; } /* Buttons - ensure contrast */ .btn, .button, .dataTables_wrapper .dataTables_paginate .paginate_button { color: var(--color-text-primary) !important; } /* If panels or overlays dim content, ensure table contents remain fully visible */ .panel, .panel-body, .table-wrapper, .dataTables_wrapper .dataTables_scrollBody { opacity: 1 !important; background: transparent !important; } /* DataTables color adjustments to ensure legibility in dark theme */ .dataTables_wrapper, .dataTables_wrapper * { color: var(--color-text-primary) !important; } .dataTables_wrapper .dataTables_info, .dataTables_wrapper .dataTables_paginate { color: var(--color-text-primary) !important; } .dataTables_wrapper .dataTables_paginate .paginate_button { background: transparent; color: var(--color-text-primary) !important; border: 1px solid transparent; border-radius: 6px; padding: 4px 8px; } .dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover { background: var(--color-primary) !important; color: var(--color-on-primary) !important; border-color: rgba(255,255,255,0.06); } /* Global legibility overrides */ body, .ots-content, .content, .container, .card, .panel, .panel-body, .table, .dataTables_wrapper, .dropdown-menu, .dropdown-right { color: var(--color-text-primary) !important; } .text-muted, .text-secondary, .text-tertiary { color: var(--color-text-secondary) !important; opacity: 1 !important; } .ots-sidebar a, .ots-sidebar .nav-item, .ots-sidebar .nav-label, .ots-sidebar .nav-text { color: var(--color-text-primary) !important; } a, .nav-link { color: var(--color-text-primary); } a:hover, .nav-link:hover { color: var(--color-primary); } /* ============================================================================ COMPREHENSIVE DARK THEME ENFORCEMENT Ensure all elements have readable contrast and dark backgrounds ============================================================================ */ /* Force ALL text to be readable - master override */ * { color-scheme: dark; } /* Ensure headings are always visible */ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { color: var(--color-text-primary) !important; } /* All labels must be readable */ label, .label, .form-label, legend { color: var(--color-text-primary) !important; } /* Dropdowns, modals, and popovers */ .dropdown-menu, .dropdown-toggle, .popover { background-color: var(--color-surface) !important; color: var(--color-text-primary) !important; border: 1px solid var(--color-border) !important; } .modal, .modal-body, .modal-footer { background-color: transparent !important; color: var(--color-text-primary) !important; border: 1px solid var(--color-border) !important; } .modal-content { background-color: var(--color-surface) !important; color: var(--color-text-primary) !important; border: 1px solid var(--color-border) !important; } .modal-backdrop, .modal-backdrop.show, .modal-backdrop.in { background-color: rgba(0, 0, 0, 0.3) !important; backdrop-filter: blur(4px) !important; opacity: 1 !important; } .modal-header { background-color: var(--color-surface-elevated) !important; border-bottom: 1px solid var(--color-border) !important; } .dropdown-menu a, .dropdown-item { color: var(--color-text-primary) !important; } .dropdown-menu a:hover, .dropdown-item:hover { background-color: rgba(59, 130, 246, 0.12) !important; color: var(--color-primary) !important; } /* Ensure form elements are dark and readable */ .form-group, .form-check, .input-group { color: var(--color-text-primary) !important; } input, textarea, select, .form-control, .form-select { background-color: var(--color-surface) !important; color: var(--color-text-primary) !important; border: 1px solid var(--color-border) !important; } input::placeholder, textarea::placeholder { color: var(--color-text-secondary) !important; } input:focus, textarea:focus, select:focus { background-color: var(--color-surface) !important; color: var(--color-text-primary) !important; border-color: var(--color-primary) !important; box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1) !important; } /* Alerts and messages */ .alert, .alert-info, .alert-warning, .alert-success, .alert-danger, .alert-light { background-color: var(--color-surface) !important; border: 1px solid var(--color-border) !important; color: var(--color-text-primary) !important; } .alert-light { background-color: var(--color-surface-elevated) !important; } /* Tooltips and help text */ .tooltip, .tooltip-inner, .help-block, .form-text, small { color: var(--color-text-secondary) !important; background-color: transparent !important; } /* Breadcrumbs */ .breadcrumb { background-color: transparent !important; color: var(--color-text-primary) !important; } .breadcrumb a { color: var(--color-primary) !important; } .breadcrumb-item.active { color: var(--color-text-secondary) !important; } /* Pagination */ .pagination, .pager { background-color: transparent !important; } .pagination a, .pagination button, .pager a { color: var(--color-text-primary) !important; background-color: transparent !important; border: 1px solid var(--color-border) !important; } .pagination a:hover, .pagination button:hover, .pager a:hover { background-color: var(--color-surface) !important; color: var(--color-primary) !important; border-color: var(--color-primary) !important; } .pagination .active a, .pagination .active button, .pager .active a { background-color: var(--color-primary) !important; border-color: var(--color-primary) !important; color: white !important; } /* Disabled state */ [disabled], :disabled, .disabled { opacity: 0.6 !important; color: var(--color-text-secondary) !important; } /* Badge customization */ .badge, .badge-default { background-color: var(--color-surface-elevated) !important; color: var(--color-text-primary) !important; } /* List groups */ .list-group, .list-group-item { background-color: var(--color-surface) !important; color: var(--color-text-primary) !important; border: 1px solid var(--color-border) !important; } .list-group-item:hover { background-color: var(--color-surface-elevated) !important; } .list-group-item.active { background-color: var(--color-primary) !important; border-color: var(--color-primary) !important; color: white !important; } /* Tabs */ .nav-tabs, .nav-pills { background-color: transparent !important; } .nav-tabs .nav-link, .nav-pills .nav-link { color: var(--color-text-secondary) !important; background-color: transparent !important; } .nav-tabs .nav-link:hover, .nav-pills .nav-link:hover { color: var(--color-text-primary) !important; background-color: rgba(59, 130, 246, 0.1) !important; } .nav-tabs .nav-link.active, .nav-pills .nav-link.active { color: white !important; background-color: var(--color-primary) !important; border-color: var(--color-primary) !important; } /* Cards */ .card { background-color: var(--color-surface) !important; color: var(--color-text-primary) !important; border: 1px solid var(--color-border) !important; } .card-header { background-color: var(--color-surface-elevated) !important; border-bottom: 1px solid var(--color-border) !important; color: var(--color-text-primary) !important; } .card-footer { background-color: var(--color-surface-elevated) !important; border-top: 1px solid var(--color-border) !important; color: var(--color-text-secondary) !important; } /* Progress bars */ .progress { background-color: var(--color-surface-elevated) !important; } .progress-bar { background-color: var(--color-primary) !important; } /* Ensure code blocks are readable */ code, .code, pre { background-color: var(--color-surface-elevated) !important; color: var(--color-text-primary) !important; border: 1px solid var(--color-border) !important; } /* DataTables specific overrides */ .dataTables_wrapper { color: var(--color-text-primary) !important; } .dataTables_wrapper .dataTables_info, .dataTables_wrapper .dataTables_paginate { background-color: transparent !important; color: var(--color-text-primary) !important; } .dataTables_wrapper table tbody tr { color: var(--color-text-primary) !important; } .dataTables_wrapper table tbody tr:hover { background-color: rgba(59, 130, 246, 0.08) !important; } /* Spinner/loading indicators */ .spinner, .spinner-border, .spinner-grow { border-color: rgba(255, 255, 255, 0.25) !important; } .spinner-border.text-primary, .spinner-grow.text-primary { color: var(--color-primary) !important; border-color: var(--color-primary) !important; } /* Links should always be visible and contrasting */ a { color: var(--color-primary) !important; text-decoration: none; } a:hover { color: var(--color-primary-light) !important; text-decoration: underline; } a.text-muted { color: var(--color-text-secondary) !important; } a.text-muted:hover { color: var(--color-text-primary) !important; } /* Ensure absolutely nothing is invisible */ .hidden, [hidden] { display: none !important; } .invisible { visibility: hidden !important; } /* ============================================================================= OTS SIGNAGE DARK THEME (REBUILT) February 4, 2026 ============================================================================= */ :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: #7f8aa3; --ots-primary: #4f8cff; --ots-primary-2: #2f6bff; --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: 6px; --ots-radius-md: 10px; --ots-radius-lg: 14px; --ots-transition: 160ms ease; } /* ============================================================================= GLOBAL ============================================================================= */ html, body { background: var(--ots-bg); color: var(--ots-text); } body { font-family: "Inter", "Segoe UI", Roboto, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; } 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); } /* ============================================================================= 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); box-shadow: var(--ots-shadow-sm); } .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(79, 140, 255, 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); } /* OTS sidebar override marker */ .ots-sidebar-wrapper { box-shadow: inset 0 0 0 1px rgba(79, 140, 255, 0.2); } .ots-sidebar .sidebar-list a, .ots-sidebar .sidebar-main a { display: flex; align-items: center; gap: 10px; } .ots-nav-icon { width: 18px; text-align: center; opacity: 0.85; font-size: 14px; } .ots-nav-text { flex: 1; min-width: 0; } /* Xibo sidebar refinements (dark) */ #sidebar-wrapper .sidebar-title a { color: var(--ots-text-faint); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; padding: 12px 16px 6px; } #sidebar-wrapper .sidebar-list a, #sidebar-wrapper .sidebar-main a { display: block; margin: 2px 8px; padding: 10px 12px; border-radius: var(--ots-radius-sm); transition: background var(--ots-transition), color var(--ots-transition); } #sidebar-wrapper .sidebar-list a:hover, #sidebar-wrapper .sidebar-main a:hover { background: rgba(79, 140, 255, 0.12); color: var(--ots-primary); } #sidebar-wrapper .sidebar { padding: 14px 0; } #sidebar-wrapper .sidebar-main a, #sidebar-wrapper .sidebar-list a { display: block; padding: 10px 18px; color: var(--ots-text); border-left: 3px solid transparent; } #sidebar-wrapper .sidebar-main a:hover, #sidebar-wrapper .sidebar-list a:hover { background: rgba(79, 140, 255, 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(--color-surface) !important; border: 1px solid var(--color-border) !important; border-radius: var(--radius-md); box-shadow: var(--shadow-base); } .widget-title, .panel-heading, .card-header, .modal-header { background: var(--color-surface-elevated) !important; border-bottom: 1px solid var(--color-border) !important; color: var(--color-text-primary) !important; } .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(79, 140, 255, 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(79, 140, 255, 0.04); } .table-hover > tbody > tr:hover { background: rgba(79, 140, 255, 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(79, 140, 255, 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 ============================================================================= */ .modal-content { border-radius: var(--radius-lg); background-color: var(--color-surface) !important; color: var(--color-text-primary) !important; border: 1px solid var(--color-border) !important; } .modal, .modal-header, .modal-body, .modal-footer { background-color: transparent !important; color: var(--color-text-primary) !important; } .modal-backdrop, .modal-backdrop.show, .modal-backdrop.in { background-color: rgba(0, 0, 0, 0.3) !important; backdrop-filter: blur(4px) !important; opacity: 1 !important; } .modal-footer { border-top: 1px solid var(--ots-border); } /* ============================================================================= HELP PANE / MISC ============================================================================= */ #help-pane { background: var(--ots-surface-2); border: 1px solid var(--ots-border); } #help-pane .help-pane-btn { background: var(--ots-primary); color: #0b1020; } /* ============================================================================= OTS DASHBOARD MESSAGE ============================================================================= */ .ots-dashboard-message { margin: 16px 0 24px; padding: 12px 16px; border-radius: var(--ots-radius-md); background: rgba(79, 140, 255, 0.16); border: 1px solid rgba(79, 140, 255, 0.45); 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); }