The <=600px header collapsed the search to a floating 32px circle, which left ~250px of empty bar at 600px and hid the primary action behind a tap even though the width supported a real field. - The phone breakpoint moves to 520px: at 521px the icon nav and the 200px search floor still coexist, and 480-600px keep their tabs. - Below that the search is an always-visible pill that fills the row and the current page name sits next to the logo, so the bar still says where you are now that the tabs live in the menu. - Drops the click-to-expand overlay and its Escape handler: no fixed positioning, no transparent placeholder, no breakpoint duplicated in JS. - Active menu entry uses an accent tint; the hover token it used before has no dark-mode value. Verified 320-1920px: no clipping or overlap, page title appears at 381-520px and the menu carries all seven tabs.
967 lines
22 KiB
CSS
967 lines
22 KiB
CSS
.app-header {
|
|
background: var(--card-bg);
|
|
border-bottom: 1px solid var(--border-color);
|
|
position: fixed;
|
|
top: 0;
|
|
z-index: var(--z-header);
|
|
height: var(--header-height, 48px);
|
|
/* Reduced height */
|
|
width: 100%;
|
|
box-shadow: var(--shadow-md);
|
|
/* Slightly stronger shadow */
|
|
}
|
|
|
|
.header-container {
|
|
max-width: none;
|
|
margin: 0 auto;
|
|
padding: 0 15px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
height: 100%;
|
|
gap: 1rem;
|
|
}
|
|
|
|
/* Left section: Logo + Navigation */
|
|
.header-left {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* Right section: Controls */
|
|
.header-right {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* Logo and title styling */
|
|
.header-branding {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.logo-link {
|
|
display: flex;
|
|
align-items: center;
|
|
text-decoration: none;
|
|
color: var(--text-color);
|
|
gap: 8px;
|
|
}
|
|
|
|
.app-logo {
|
|
width: 24px;
|
|
height: 24px;
|
|
}
|
|
|
|
.app-title {
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
margin: 0;
|
|
}
|
|
|
|
/* Current page name, shown next to the logo on phone widths where the tab bar
|
|
lives in the hamburger menu - without it the bar gives no sense of place. */
|
|
.page-title {
|
|
display: none;
|
|
margin-left: 8px;
|
|
max-width: 7rem;
|
|
overflow: hidden;
|
|
font-size: 0.9rem;
|
|
font-weight: 600;
|
|
color: var(--text-color);
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
/* Navigation styling */
|
|
.main-nav {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.nav-item {
|
|
padding: 0.25rem 0.75rem;
|
|
border-radius: var(--border-radius-xs);
|
|
color: var(--text-color);
|
|
text-decoration: none;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
font-size: 0.9rem;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Opt-in pages (e.g. Other Models) hide their nav entry until enabled.
|
|
A class is used instead of [hidden] because .nav-item sets display: flex. */
|
|
.nav-item--hidden {
|
|
display: none;
|
|
}
|
|
|
|
.nav-item:hover,
|
|
.nav-item:focus-visible {
|
|
background-color: var(--lora-surface-hover, oklch(95% 0.02 256));
|
|
color: var(--lora-accent);
|
|
}
|
|
|
|
.nav-item:hover i,
|
|
.nav-item:hover span,
|
|
.nav-item:focus-visible i,
|
|
.nav-item:focus-visible span {
|
|
color: inherit;
|
|
}
|
|
|
|
.nav-item.active {
|
|
background-color: var(--lora-accent);
|
|
color: var(--text-on-accent);
|
|
}
|
|
|
|
/* Header search - Centered with VS Code command palette style */
|
|
.header-search {
|
|
flex: 1;
|
|
display: flex;
|
|
justify-content: center;
|
|
max-width: 600px;
|
|
/* No hard floor: the field shrinks with the available space instead of parking
|
|
at a fixed width and crowding its own placeholder (see the 1366px query). */
|
|
min-width: 0;
|
|
margin: 0 auto;
|
|
transition: opacity 0.2s ease;
|
|
}
|
|
|
|
/* VS Code command palette style search container */
|
|
.header-search .search-container {
|
|
width: 100%;
|
|
max-width: 600px;
|
|
min-width: 0;
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
background: var(--input-bg, var(--card-bg));
|
|
border: 1px solid var(--border-color);
|
|
border-radius: var(--border-radius-sm, 6px);
|
|
transition: border-color var(--transition-base), box-shadow var(--transition-base);
|
|
box-shadow: var(--shadow-header);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.header-search .search-container:focus-within {
|
|
border-color: var(--lora-accent);
|
|
box-shadow: var(--shadow-header), 0 0 0 1px var(--lora-accent);
|
|
}
|
|
|
|
.header-search input {
|
|
flex: 1;
|
|
width: 100%;
|
|
padding: 0.5rem 0.75rem;
|
|
padding-left: 2.25rem !important;
|
|
/* Reserve exactly the inline chrome so typed text never runs under it:
|
|
cue(58) + clear(28) + toggles(28 + 28 + 4 gap) + edges(8 + 8) = 126px.
|
|
Below 1366px the cue is hidden and the reservation drops to 68px.
|
|
!important is required: search-filter.css loads later and sets its own
|
|
right padding at equal specificity (.search-container input). */
|
|
padding-right: 7.875rem !important;
|
|
border: none;
|
|
background: transparent;
|
|
color: var(--text-color);
|
|
font-size: 0.95rem;
|
|
outline: none;
|
|
}
|
|
|
|
.header-search input::placeholder {
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.header-search .search-icon {
|
|
position: absolute;
|
|
left: 0.75rem;
|
|
color: var(--text-muted);
|
|
font-size: 0.9rem;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.header-search .search-options-toggle,
|
|
.header-search .search-filter-toggle {
|
|
position: absolute;
|
|
right: 0.5rem;
|
|
width: 28px;
|
|
height: 28px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: transparent;
|
|
border: none;
|
|
color: var(--text-muted);
|
|
cursor: pointer;
|
|
border-radius: var(--border-radius-xs, 4px);
|
|
transition: background-color var(--transition-base), color var(--transition-base);
|
|
}
|
|
|
|
.header-search .search-options-toggle {
|
|
right: 2.25rem;
|
|
}
|
|
|
|
/* Clear button: sit immediately left of the search-options toggle */
|
|
.header-search .search-clear {
|
|
position: absolute;
|
|
right: 4.25rem; /* 2.25rem (options toggle) + 28px toggle width + 4px gap */
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
width: 28px;
|
|
height: 28px;
|
|
display: none;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: transparent;
|
|
border: none;
|
|
color: var(--text-muted);
|
|
cursor: pointer;
|
|
border-radius: var(--border-radius-xs, 4px);
|
|
padding: 0;
|
|
line-height: 1;
|
|
transition: background-color var(--transition-base), color var(--transition-base);
|
|
}
|
|
|
|
.header-search .search-clear.visible {
|
|
display: flex;
|
|
}
|
|
|
|
.header-search .search-clear:hover {
|
|
background: color-mix(in oklch, var(--text-muted) 15%, transparent);
|
|
color: var(--lora-accent);
|
|
}
|
|
|
|
/* Keyboard shortcut cue: shown when search is empty, hidden when typing */
|
|
.header-search .search-shortcut-cue {
|
|
position: absolute;
|
|
right: 4.25rem; /* same slot as clear button */
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 2px;
|
|
pointer-events: none;
|
|
font-family: inherit;
|
|
font-size: 0.7rem;
|
|
line-height: 1;
|
|
color: var(--text-muted);
|
|
opacity: 0.7;
|
|
white-space: nowrap;
|
|
transition: opacity 0.2s ease;
|
|
}
|
|
|
|
.header-search .search-shortcut-cue kbd {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-width: 18px;
|
|
height: 18px;
|
|
padding: 0 4px;
|
|
font-family: inherit;
|
|
font-size: 0.68rem;
|
|
font-weight: 500;
|
|
color: var(--shortcut-text);
|
|
background: var(--shortcut-bg);
|
|
border: 1px solid var(--shortcut-border);
|
|
box-shadow: var(--shortcut-shadow);
|
|
border-radius: var(--border-radius-xs, 3px);
|
|
line-height: 1;
|
|
}
|
|
|
|
.header-search .search-shortcut-cue.hidden {
|
|
display: none;
|
|
}
|
|
|
|
.header-search.disabled .search-shortcut-cue {
|
|
display: none;
|
|
}
|
|
|
|
.header-search .search-options-toggle:hover,
|
|
.header-search .search-filter-toggle:hover,
|
|
.header-search .search-filter-toggle:focus-visible {
|
|
background: var(--lora-surface-hover, oklch(95% 0.02 256));
|
|
color: var(--lora-accent);
|
|
outline: none;
|
|
}
|
|
|
|
.header-search .filter-badge {
|
|
position: absolute;
|
|
top: 2px;
|
|
right: 2px;
|
|
width: 8px;
|
|
height: 8px;
|
|
background: var(--lora-accent);
|
|
border-radius: 50%;
|
|
font-size: 0;
|
|
}
|
|
|
|
/* Disabled state for header search */
|
|
.header-search.disabled {
|
|
opacity: 0.5;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.header-search.disabled input {
|
|
background-color: var(--input-disabled-bg, #f5f5f5);
|
|
color: var(--text-muted);
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.header-search.disabled button {
|
|
background-color: var(--button-disabled-bg, #e0e0e0);
|
|
color: var(--text-muted);
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.header-search.disabled .search-icon {
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* Dark theme specific styles for disabled header search */
|
|
[data-theme="dark"] .header-search.disabled input {
|
|
background-color: #3a3a3a;
|
|
color: #888888;
|
|
border-color: #555555;
|
|
}
|
|
|
|
[data-theme="dark"] .header-search.disabled button {
|
|
background-color: #3a3a3a;
|
|
color: #888888;
|
|
border-color: #555555;
|
|
}
|
|
|
|
[data-theme="dark"] .header-search.disabled .search-icon {
|
|
color: #888888;
|
|
}
|
|
|
|
[data-theme="dark"] .header-search.disabled .fas {
|
|
color: #888888;
|
|
}
|
|
|
|
/* Header controls (formerly corner controls) */
|
|
.header-controls {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.header-controls>div {
|
|
width: 32px;
|
|
height: 32px;
|
|
border-radius: 50%;
|
|
background: var(--card-bg);
|
|
border: 1px solid var(--border-color);
|
|
color: var(--text-color);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
cursor: pointer;
|
|
transition: background-color var(--transition-base), color var(--transition-base), transform var(--transition-base);
|
|
position: relative;
|
|
}
|
|
|
|
.header-controls>div:hover {
|
|
background: var(--lora-accent);
|
|
color: var(--text-on-accent);
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.theme-toggle {
|
|
position: relative;
|
|
}
|
|
|
|
.theme-toggle .light-icon,
|
|
.theme-toggle .dark-icon,
|
|
.theme-toggle .auto-icon {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
|
|
.theme-toggle .dark-icon {
|
|
opacity: 1;
|
|
}
|
|
|
|
.theme-toggle.theme-light .light-icon {
|
|
opacity: 1;
|
|
}
|
|
|
|
.theme-toggle.theme-light .dark-icon,
|
|
.theme-toggle.theme-light .auto-icon {
|
|
opacity: 0;
|
|
}
|
|
|
|
.theme-toggle.theme-dark .dark-icon {
|
|
opacity: 1;
|
|
}
|
|
|
|
.theme-toggle.theme-dark .light-icon,
|
|
.theme-toggle.theme-dark .auto-icon {
|
|
opacity: 0;
|
|
}
|
|
|
|
.theme-toggle.theme-auto .auto-icon {
|
|
opacity: 1;
|
|
}
|
|
|
|
.theme-toggle.theme-auto .light-icon,
|
|
.theme-toggle.theme-auto .dark-icon {
|
|
opacity: 0;
|
|
}
|
|
|
|
.theme-popover {
|
|
display: none;
|
|
position: fixed;
|
|
background: var(--surface-base, #ffffff);
|
|
border: 1px solid var(--border-base, #e0e0e0);
|
|
border-radius: var(--radius-md, 8px);
|
|
box-shadow: var(--shadow-xl, 0 4px 16px rgba(0, 0, 0, 0.15));
|
|
padding: 12px;
|
|
min-width: 220px;
|
|
z-index: calc(var(--z-overlay) + 1);
|
|
animation: theme-popover-in 0.15s ease-out;
|
|
}
|
|
|
|
.theme-popover.active {
|
|
display: block;
|
|
}
|
|
|
|
@keyframes theme-popover-in {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(-4px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
.theme-popover-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
}
|
|
|
|
.theme-popover-label {
|
|
font-size: 0.7rem;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
color: var(--text-secondary, #6c757d);
|
|
}
|
|
|
|
.theme-popover-divider {
|
|
height: 1px;
|
|
background: var(--border-base, #e0e0e0);
|
|
margin: 10px 0;
|
|
}
|
|
|
|
.theme-popover-modes {
|
|
display: flex;
|
|
gap: 6px;
|
|
}
|
|
|
|
.theme-mode-btn {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 4px;
|
|
padding: 8px 4px;
|
|
border: 1px solid var(--border-base, #e0e0e0);
|
|
border-radius: var(--radius-sm, 6px);
|
|
background: var(--surface-elevated, #ffffff);
|
|
color: var(--text-primary, #333333);
|
|
cursor: pointer;
|
|
font-size: 0.75rem;
|
|
transition: background-color var(--transition-base, 200ms ease),
|
|
border-color var(--transition-base, 200ms ease),
|
|
color var(--transition-base, 200ms ease);
|
|
}
|
|
|
|
.theme-mode-btn i {
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.theme-mode-btn:hover {
|
|
background: var(--surface-hover, oklch(95% 0.02 256));
|
|
border-color: var(--color-accent, oklch(68% 0.28 256));
|
|
}
|
|
|
|
.theme-mode-btn.active {
|
|
background: var(--color-accent-subtle, oklch(68% 0.28 256 / 0.12));
|
|
border-color: var(--color-accent, oklch(68% 0.28 256));
|
|
color: var(--color-accent, oklch(68% 0.28 256));
|
|
}
|
|
|
|
.theme-popover-presets {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, 1fr);
|
|
gap: 6px;
|
|
}
|
|
|
|
.theme-preset-btn {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 4px;
|
|
padding: 8px 4px;
|
|
border: 1px solid var(--border-base, #e0e0e0);
|
|
border-radius: var(--radius-sm, 6px);
|
|
background: var(--surface-elevated, #ffffff);
|
|
color: var(--text-primary, #333333);
|
|
cursor: pointer;
|
|
font-size: 0.7rem;
|
|
transition: background-color var(--transition-base, 200ms ease),
|
|
border-color var(--transition-base, 200ms ease),
|
|
color var(--transition-base, 200ms ease);
|
|
}
|
|
|
|
.theme-preset-btn:hover {
|
|
background: var(--surface-hover, oklch(95% 0.02 256));
|
|
border-color: var(--color-accent, oklch(68% 0.28 256));
|
|
}
|
|
|
|
.theme-preset-btn.active {
|
|
background: var(--color-accent-subtle, oklch(68% 0.28 256 / 0.12));
|
|
border-color: var(--color-accent, oklch(68% 0.28 256));
|
|
color: var(--color-accent, oklch(68% 0.28 256));
|
|
}
|
|
|
|
.preset-swatch {
|
|
display: inline-block;
|
|
width: 22px;
|
|
height: 22px;
|
|
border-radius: var(--radius-xs, 4px);
|
|
border: 1px solid var(--border-subtle, oklch(72% 0.03 256 / 0.45));
|
|
flex-shrink: 0;
|
|
transition: transform var(--transition-base, 200ms ease),
|
|
box-shadow var(--transition-base, 200ms ease);
|
|
}
|
|
|
|
/* Solid accent colors — each swatch shows the theme's accent color directly.
|
|
This matches the app's flat, token-driven design language instead of using
|
|
decorative gradients that clash with the matte aesthetic. */
|
|
|
|
.preset-swatch-default {
|
|
background: oklch(68% 0.28 256);
|
|
}
|
|
|
|
.preset-swatch-nord {
|
|
background: oklch(62% 0.18 213);
|
|
}
|
|
|
|
.preset-swatch-midnight {
|
|
background: oklch(52% 0.15 300);
|
|
}
|
|
|
|
.preset-swatch-monokai {
|
|
background: oklch(72% 0.24 190);
|
|
}
|
|
|
|
.preset-swatch-dracula {
|
|
background: oklch(68% 0.24 265);
|
|
}
|
|
|
|
.preset-swatch-solarized {
|
|
background: oklch(55% 0.18 175);
|
|
}
|
|
|
|
.theme-preset-btn.active .preset-swatch {
|
|
box-shadow: 0 0 0 2px var(--color-accent, oklch(68% 0.28 256));
|
|
}
|
|
|
|
.theme-preset-btn:hover .preset-swatch {
|
|
transform: scale(1.08);
|
|
}
|
|
|
|
/* Dark mode: use each preset's dark-mode accent lightness for visibility.
|
|
These match the --color-accent-l values from :root[data-theme="dark"][data-theme-preset="..."]
|
|
in tokens/colors.css so the swatch accurately previews what the theme looks like. */
|
|
|
|
[data-theme="dark"] .preset-swatch-default {
|
|
background: oklch(68% 0.28 256);
|
|
}
|
|
|
|
[data-theme="dark"] .preset-swatch-nord {
|
|
background: oklch(68% 0.18 213);
|
|
}
|
|
|
|
[data-theme="dark"] .preset-swatch-midnight {
|
|
background: oklch(68% 0.14 300);
|
|
}
|
|
|
|
[data-theme="dark"] .preset-swatch-monokai {
|
|
background: oklch(72% 0.24 190);
|
|
}
|
|
|
|
[data-theme="dark"] .preset-swatch-dracula {
|
|
background: oklch(72% 0.24 265);
|
|
}
|
|
|
|
[data-theme="dark"] .preset-swatch-solarized {
|
|
background: oklch(60% 0.18 175);
|
|
}
|
|
|
|
/* Badge styling */
|
|
.update-badge {
|
|
position: absolute;
|
|
top: -3px;
|
|
right: -3px;
|
|
width: 8px;
|
|
height: 8px;
|
|
background-color: var(--lora-error);
|
|
border-radius: 50%;
|
|
border: 2px solid var(--card-bg);
|
|
transition: opacity var(--transition-base);
|
|
pointer-events: none;
|
|
opacity: 0;
|
|
}
|
|
|
|
.update-badge.visible {
|
|
opacity: 1;
|
|
}
|
|
|
|
/* Hamburger menu button - hidden by default */
|
|
.hamburger-menu-btn {
|
|
display: none;
|
|
width: 32px;
|
|
height: 32px;
|
|
border-radius: 50%;
|
|
background: var(--card-bg);
|
|
border: 1px solid var(--border-color);
|
|
color: var(--text-color);
|
|
align-items: center;
|
|
justify-content: center;
|
|
cursor: pointer;
|
|
transition: background-color var(--transition-base), color var(--transition-base);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.hamburger-menu-btn:hover,
|
|
.hamburger-menu-btn:focus-visible {
|
|
background: var(--lora-surface-hover, oklch(95% 0.02 256));
|
|
color: var(--lora-accent);
|
|
outline: none;
|
|
}
|
|
|
|
.hamburger-dropdown .dropdown-item:hover,
|
|
.hamburger-dropdown .dropdown-item:focus-visible {
|
|
background: var(--lora-surface-hover, oklch(95% 0.02 256));
|
|
color: var(--lora-accent);
|
|
outline: none;
|
|
}
|
|
|
|
/* Hamburger dropdown menu */
|
|
.hamburger-dropdown {
|
|
display: none;
|
|
position: absolute;
|
|
top: 100%;
|
|
right: 0;
|
|
margin-top: 8px;
|
|
background: var(--card-bg);
|
|
border: 1px solid var(--border-color);
|
|
border-radius: var(--border-radius-sm, 6px);
|
|
box-shadow: var(--shadow-toast);
|
|
padding: 0.5rem;
|
|
min-width: 160px;
|
|
z-index: var(--z-dropdown, 200);
|
|
}
|
|
|
|
.hamburger-dropdown.active {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.25rem;
|
|
}
|
|
|
|
.hamburger-dropdown .dropdown-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
padding: 0.5rem 0.75rem;
|
|
border-radius: var(--border-radius-xs, 4px);
|
|
color: var(--text-color);
|
|
cursor: pointer;
|
|
transition: background-color var(--transition-base), color var(--transition-base);
|
|
font-size: 0.9rem;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.hamburger-dropdown .dropdown-item:hover {
|
|
background: var(--lora-surface-hover, oklch(95% 0.02 256));
|
|
color: var(--lora-accent);
|
|
}
|
|
|
|
.hamburger-dropdown .dropdown-item i {
|
|
width: 20px;
|
|
text-align: center;
|
|
}
|
|
|
|
.hamburger-dropdown .dropdown-divider {
|
|
height: 1px;
|
|
background: var(--border-color);
|
|
margin: 0.25rem 0;
|
|
}
|
|
|
|
/* Page tabs inside the hamburger menu. They mirror the main nav for phone
|
|
widths, where the nav itself is hidden (see the <=520px block below);
|
|
everywhere else they stay out of the menu. */
|
|
.hamburger-dropdown .hamburger-nav-item,
|
|
.hamburger-dropdown .hamburger-nav-divider {
|
|
display: none;
|
|
}
|
|
|
|
/* SettingsManager hides the opt-in entries (Other, Workflows) on both copies. */
|
|
.hamburger-dropdown .hamburger-nav-item[hidden] {
|
|
display: none !important;
|
|
}
|
|
|
|
.hamburger-nav-item.active {
|
|
color: var(--lora-accent);
|
|
/* Accent tint instead of the hover surface token, which has no dark-mode
|
|
value (its fallback is a fixed light grey). */
|
|
background: color-mix(in oklab, var(--lora-accent) 14%, transparent);
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* The menu entries are anchors (the actions are divs), so drop the UA underline. */
|
|
.hamburger-dropdown a.hamburger-nav-item {
|
|
text-decoration: none;
|
|
}
|
|
|
|
/* Responsive ladder for the header.
|
|
Worst case measured in the browser (both opt-in pages enabled, 7 tabs):
|
|
icon + label nav ≈ 783px, labels only ≈ 619px (517px once the 1366px tier
|
|
below applies). The bar also spends a fixed ~424px on padding, branding,
|
|
the five round controls and gaps. Every tier below therefore exists to keep
|
|
the search field usable - at 1280px the old ladder left it 73px wide, i.e.
|
|
nothing but its two inline toggles. */
|
|
|
|
/* ≤1500px: nav icons are a wide-screen affordance. The labels keep the tabs
|
|
scannable on their own, and dropping the icons hands ~168px back to the
|
|
search field. Above 1500px there is room for both. */
|
|
@media (max-width: 1500px) {
|
|
.nav-item {
|
|
gap: 0;
|
|
}
|
|
|
|
.nav-item i {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
/* ≤1366px: compact chrome (tighter gaps, padding and nav font), and drop the
|
|
Ctrl+F cue - it is pure decoration and the widest thing inside the field.
|
|
The shortcut itself keeps working; only the visual hint goes away. */
|
|
@media (max-width: 1366px) {
|
|
.header-container {
|
|
gap: 0.75rem;
|
|
padding: 0 12px;
|
|
}
|
|
|
|
.main-nav {
|
|
gap: 0.25rem;
|
|
}
|
|
|
|
.nav-item {
|
|
padding: 0.25rem 0.5rem;
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.header-controls {
|
|
gap: 6px;
|
|
}
|
|
|
|
.header-search .search-shortcut-cue {
|
|
display: none;
|
|
}
|
|
|
|
.header-search input {
|
|
padding-right: 4.25rem !important;
|
|
}
|
|
}
|
|
|
|
/* ≤1150px: the app title is the cheapest ~137px left in the bar - the logo
|
|
still identifies the app, while the nav labels are what people navigate by. */
|
|
@media (max-width: 1150px) {
|
|
.app-title {
|
|
display: none !important;
|
|
}
|
|
}
|
|
|
|
/* ≤1100px: collapse the five round controls into the hamburger. Its dropdown
|
|
already carries the same five actions, so nothing is lost, and the bar
|
|
reclaims ~192px for the nav and the search field. */
|
|
@media (max-width: 1100px) {
|
|
.header-controls {
|
|
display: none !important;
|
|
}
|
|
|
|
.hamburger-menu-btn {
|
|
display: flex !important;
|
|
}
|
|
|
|
.hamburger-dropdown {
|
|
display: none;
|
|
}
|
|
|
|
.hamburger-dropdown.active {
|
|
display: flex;
|
|
}
|
|
}
|
|
|
|
/* ≤950px: give the search field the whole flexible row and tighten the nav. */
|
|
@media (max-width: 950px) {
|
|
.header-container {
|
|
padding: 0 10px;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.header-search {
|
|
max-width: none;
|
|
margin: 0;
|
|
flex: 1;
|
|
min-width: 200px;
|
|
}
|
|
|
|
.main-nav {
|
|
gap: 0.25rem;
|
|
margin-right: 0;
|
|
}
|
|
|
|
.nav-item {
|
|
padding: 0.25rem 0.35rem;
|
|
font-size: 0.8rem;
|
|
}
|
|
}
|
|
|
|
/* Below 780px the labelled nav (461px) can no longer coexist with the 200px
|
|
search floor and the hamburger: the row overflowed and clipped the
|
|
hamburger by ~40px at 720px. Collapse the labels to icons (190px) and give
|
|
the width back to the search field. The tooltip + aria-label on each tab
|
|
keep the icon-only state usable. */
|
|
@media (max-width: 780px) {
|
|
.main-nav {
|
|
display: flex;
|
|
gap: 0.15rem;
|
|
margin-right: 0;
|
|
}
|
|
|
|
.nav-item {
|
|
padding: 0.25rem 0.4rem;
|
|
}
|
|
|
|
.nav-item span {
|
|
display: none;
|
|
}
|
|
|
|
.nav-item i {
|
|
display: block;
|
|
}
|
|
}
|
|
|
|
/* Responsive: Compact mode at 768px */
|
|
@media (max-width: 768px) {
|
|
.header-search input {
|
|
padding: 0.4rem 0.6rem;
|
|
padding-left: 2rem !important;
|
|
padding-right: 4.5rem !important;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.header-search .search-container {
|
|
border-radius: var(--border-radius-xs, 4px);
|
|
}
|
|
}
|
|
|
|
/* Small tablets: keep the icon tabs, tighten the chrome. */
|
|
@media (max-width: 600px) {
|
|
.header-container {
|
|
padding: 0 8px;
|
|
gap: 0.4rem;
|
|
}
|
|
|
|
.nav-item {
|
|
padding: 0.25rem;
|
|
font-size: 0.75rem;
|
|
}
|
|
|
|
.nav-item i {
|
|
font-size: 1rem;
|
|
}
|
|
}
|
|
|
|
/* Phone widths (<=520px): seven icon tabs no longer fit next to a usable search
|
|
field, so the tabs move into the hamburger menu (the template repeats them
|
|
there) and the search becomes a full-width pill: logo + page name | search |
|
|
menu. 521px is the first width where the icon nav and the 200px search floor
|
|
coexist, which is where the cut belongs. */
|
|
@media (max-width: 520px) {
|
|
.main-nav {
|
|
display: none;
|
|
}
|
|
|
|
.page-title {
|
|
display: inline-block;
|
|
}
|
|
|
|
.hamburger-dropdown .hamburger-nav-item {
|
|
display: flex;
|
|
}
|
|
|
|
.hamburger-dropdown .hamburger-nav-divider {
|
|
display: block;
|
|
}
|
|
|
|
/* The menu now holds 7 tabs + 5 actions: let it scroll on short screens. */
|
|
.hamburger-dropdown {
|
|
max-height: calc(100vh - 72px);
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.header-search {
|
|
flex: 1 1 auto;
|
|
width: auto;
|
|
min-width: 0;
|
|
max-width: none;
|
|
margin: 0 4px;
|
|
}
|
|
|
|
.header-search .search-container {
|
|
width: 100%;
|
|
border-radius: 999px;
|
|
}
|
|
|
|
.header-search input {
|
|
width: 100%;
|
|
min-width: 0;
|
|
padding: 0.4rem 0.75rem !important;
|
|
padding-left: 2rem !important;
|
|
padding-right: 4.25rem !important;
|
|
/* 16px stops mobile browsers zooming the page on focus. */
|
|
font-size: 1rem;
|
|
}
|
|
}
|
|
|
|
/* The smallest phones need the page name's width for the search field. */
|
|
@media (max-width: 380px) {
|
|
.page-title {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
/* Position relative for hamburger menu positioning */
|
|
.header-right {
|
|
position: relative;
|
|
}
|