// out: false // ========================================================================== // Layout Styles // Main layout components for LuCI admin interface // ========================================================================== // 1. Main Container Layout // ========================================================================== .main { position: relative; width: 100%; height: 100%; overflow-y: auto; display: flex; flex-direction: row; } // 2. Left Sidebar Layout // ========================================================================== .main-left { // Category colours are independent of success/warning status colours. --menu-icon-system: @orange-500; --menu-icon-services: @cyan-500; --menu-icon-network: #8965e0; --menu-icon-muted: @neutral-400; --sidebar-width: 15rem; width: var(--sidebar-width); height: 100%; flex-shrink: 0; z-index: 100; overflow-x: auto; word-break: break-word; background-color: var(--surface-raised); box-shadow: var(--sidebar-shadow); // Sidebar Header .sidenav-header { padding: 1.5rem 0.5rem; text-align: center; .brand { display: block; margin: 0 2rem; font-size: 1.8rem; font-family: "TypoGraphica"; color: var(--sidebar-brand-color); text-decoration: none; text-align: center; cursor: default; .logo { max-width: 100%; height: auto; } } } // Navigation Menu .nav { margin-top: 0.5rem; // Top-level navigation links &>li>a:first-child { display: block; position: relative; margin: 0.1rem 0.5rem; padding: 0.675rem 0 0.675rem 2.5rem; font-size: 1rem; text-decoration: none; border-radius: var(--radius-menu); cursor: default; // Active state &.active { color: var(--accent-text); background: var(--primary); &::after { transform: rotate(0deg); color: var(--accent-text); } } // Hover state @media (hover: hover) { transition: background-color .15s ease, color .15s ease; &:hover { cursor: pointer; color: var(--accent-text); background: var(--primary); } } .menu-icon { pointer-events: none; position: absolute; left: .8rem; top: 50%; width: 1rem; height: 1rem; margin-top: -.5rem; color: var(--link-color); background-color: currentColor; -webkit-mask: var(--menu-icon) center / contain no-repeat; mask: var(--menu-icon) center / contain no-repeat; } .menu-icon[data-icon="system"] { color: var(--menu-icon-system); } .menu-icon[data-icon="services"] { color: var(--menu-icon-services); } .menu-icon[data-icon="network"], .menu-icon[data-icon="vpn"] { color: var(--menu-icon-network); } .menu-icon[data-icon="logout"] { color: var(--menu-icon-muted); } &.active .menu-icon { color: var(--accent-text); } @media (hover: hover) { .menu-icon { transition: color .15s ease; } &:hover .menu-icon { color: var(--accent-text); } } } // Navigation list items li { padding: 0; cursor: pointer; user-select: none; a { display: block; color: var(--menu-color); } // Collapsible menu items &.slide { padding: 0; ul { display: none; overflow: hidden; } &:hover { background: none; } // Submenu container .slide-menu { margin: 0 0.5rem 0 2.5rem; padding: 0rem 0.5rem; &.active { display: block; } li { position: relative; margin: 0; border-radius: var(--radius-control); background: none; list-style: none; a { padding: 0.5rem 0rem; text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } // Hover indicator line &::after { position: absolute; left: 0; bottom: 0; width: 0; height: 2px; content: ""; background-color: var(--link-color); } @media (hover: hover) { &:hover { background: none; &::after { width: 100%; } } } } // Active submenu item .active { background: none; color: var(--menu-color); a { color: var(--menu-color); } &::after { position: absolute; left: 0; bottom: 0; width: 100%; height: 2px; content: ""; background-color: var(--link-color); } } } } // SVG disclosure arrow; its colour follows the link. .menu::after { content: ""; position: absolute; inset-inline-end: .75rem; top: 50%; width: 1rem; height: 1rem; margin-top: -.5rem; background-color: currentColor; -webkit-mask: var(--chevron-down-icon) center / contain no-repeat; mask: var(--chevron-down-icon) center / contain no-repeat; transform: rotate(-90deg); pointer-events: none; } } } // Scrollbar Styling &::-webkit-scrollbar { width: 5px; height: 1px; } &::-webkit-scrollbar-thumb { background-color: var(--sidebar-scrollbar); } &::-webkit-scrollbar-track { background-color: var(--surface-raised); } } // 3. Right Content Area Layout // ========================================================================== .main-right { background-color: var(--main-bg); height: 100%; flex: 1 1 0; min-width: 0; overflow-x: hidden; overflow-y: auto; display: flex; flex-direction: column; // Main Content Container &>#maincontent { min-width: 0; position: relative; z-index: 50; flex: 1; display: flex; flex-direction: column; &>.container { min-width: 0; margin: 0 var(--page-gutter) var(--section-gap); flex-grow: 1; display: flex; flex-direction: column; gap: var(--section-gap); } // Dashboard Specific Styles .Dashboard { img.svgmonochrome { filter: var(--image-filter); } color: var(--text-strong) !important; h3 { color: var(--text-strong); } p { margin-top: 3px; margin-bottom: 3px; } hr { border-top: 1px solid rgba(0, 0, 0, 1); } .dashboard-bg { background-color: var(--surface-color); } .table { width: 100%; } .settings-info { padding-top: 1em; padding-bottom: 1em; p span:nth-child(2) { max-height: 18.5px; max-width: inherit; top: 4px; } .label { font-size: 0.7rem; padding: 0.2rem 0.6rem; } } } } } // 4. Header Layout // ========================================================================== header { position: relative; width: 100%; padding: 0; color: var(--text-on-accent); // Primary background modifier &.bg-primary { background-color: var(--header-bg); } // Header extension background &::after { content: ""; position: absolute; width: 100%; height: 2rem; background-color: var(--header-bg); } // Header Content Container .fill { padding: 0.8rem 0; display: flex; border: 0; .container { width: 100%; min-width: 0; min-height: 2rem; padding: 0 var(--page-gutter); display: flex; align-items: center; flex-wrap: wrap; gap: var(--control-gap) var(--action-gap); // Left section (brand and menu toggle) .flex1 { display: flex; flex: 1 1 10rem; align-items: center; min-width: 0; gap: var(--action-gap); .showSide { flex: 0 0 auto; font-size: 1.4rem; color: var(--text-on-accent); border: 0; background: none; cursor: pointer; &:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; } &:hover { text-decoration: none; } } .brand { display: none; min-width: 0; max-width: 100%; line-height: 1.4; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 1.5rem; font-family: "TypoGraphica"; color: var(--text-on-accent); text-decoration: none; cursor: default; vertical-align: text-bottom; } } // Right section (status indicators) .pull-right { margin-inline-start: auto; display: flex; } } // Status Indicators .status { display: flex; flex: 0 1 auto; flex-wrap: wrap; align-items: center; min-width: 0; max-width: 100%; margin-inline-start: auto; gap: var(--control-gap); span { display: inline-block; max-width: 100%; padding: 0.3rem 0.8rem; font-size: 0.875rem; font-weight: bold; white-space: normal; overflow-wrap: anywhere; text-decoration: none; text-shadow: none; border-radius: var(--radius-control); cursor: pointer; box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 2px 0 rgba(0, 0, 0, 0.12); } span[data-indicator="poll-status"] { color: var(--text-on-accent); } span[data-style="active"] { background-color: var(--success-bg); } span[data-style="inactive"] { color: var(--text-on-accent); background-color: var(--status-neutral-bg); } } } } #xhr_poll_status { display: flex; * { color: var(--text-on-accent); } } header .showSide { display: none; } // 5. Footer Layout // ========================================================================== footer { padding: 1rem; font-size: 0.875rem; color: #aaa; text-align: right; white-space: nowrap; overflow: hidden; >a { color: #aaa; text-decoration: none; } } // 6. View // ========================================================================== #view { border-radius: var(--radius-card); display: flex; flex-direction: column; min-width: 0; gap: var(--section-gap); &>.spinning { --spinner-inset: 1rem; position: fixed; top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%); padding: 1rem; border-radius: var(--radius-panel); background: var(--surface-color); box-shadow: var(--section-shadow); } &>div:first-child:not(.cbi-map) { display: flex; flex-direction: column; min-width: 0; gap: var(--field-gap); } } // Rotate one SVG so opening, closing and reversing remain continuous. @media (prefers-reduced-motion: no-preference) { .main-left { transition: width .2s ease; } .main-left .nav .menu::after { transition: transform .2s ease; } @media (hover: hover) { .main-left .nav .slide-menu li::after { transition: width .2s ease; } } } // Right-facing disclosures follow reading direction; down-facing ones do not. [dir="rtl"] .main-left .nav .menu:not(.active)::after { transform: rotate(90deg); }