38686-vm/static/css/custom.css
Konrad du Plessis b52ae47257 CSS: inline-filter pill-dropdown styling
Adds five new style components beneath the existing .filter-pill rules:

1. .filter-pill--editable   — pointer cursor, hover tint, chevron rotation
2. .filter-pill--dirty      — accent outline + pulsing orange dot
3. .filter-popover          — absolute-positioned dropdown with shadow;
                               on mobile (<576px) anchors to bottom of
                               viewport full-width
4. .apply-filters-group     — slide-in animation on the Apply/Reset buttons
5. .filter-toast-container  — fixed top-right stack for cross-filter
                               auto-remove notices; slide-in/out animations

All colours via existing design tokens (--accent, --bg-card,
--text-primary, --border-default, --bg-inset) so dark + light themes
work automatically. z-index layering (popover 1040, toast 1060) stays
below Bootstrap modals (1055+) to avoid stacking conflicts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:47:52 +02:00

1891 lines
50 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ===================================================================
FoxFitt LabourPay v5 — Premium Orange Theme
Dark-first design system with warm amber/orange accents.
Top bar navigation on desktop, bottom tab bar on mobile.
All colours are CSS variables — the theme toggle switches them.
=================================================================== */
/* === DARK MODE (default — premium dark-first design) === */
:root {
/* Brand — warm orange/amber accent */
--accent: #e8851a;
--accent-hover: #f59e0b;
--accent-subtle: rgba(232, 133, 26, 0.12);
--accent-text: #f59e0b;
--accent-glow: rgba(232, 133, 26, 0.25);
/* Surfaces — very dark, charcoal-navy */
--bg-body: #0c0e14;
--bg-card: #161921;
--bg-card-hover: #1c2029;
--bg-elevated: #1c2029;
--bg-inset: #111318;
--bg-input: #1a1d26;
--bg-nav: #0c0e14;
--bg-sidebar: #111318;
/* Borders — subtle with slight warm tint */
--border-default: rgba(255, 255, 255, 0.08);
--border-subtle: rgba(255, 255, 255, 0.04);
--border-strong: rgba(255, 255, 255, 0.15);
--border-accent: rgba(232, 133, 26, 0.3);
/* Text — softened white (~85% brightness) for easier reading on dark backgrounds */
--text-primary: #d8d8d8;
--text-secondary: #9ca3af;
--text-tertiary: #6b7280;
--text-on-accent: #ffffff;
--text-on-nav: #d8d8d8;
--text-on-nav-muted: #6b7280;
--text-link: #e8851a;
/* Override Bootstrap */
--bs-body-color: #d8d8d8;
--bs-body-bg: #0c0e14;
--bs-border-color: rgba(255, 255, 255, 0.08);
/* Shadows — deep with orange tint */
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.5);
--shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.5);
--shadow-xl: 0 20px 40px rgba(0, 0, 0, 0.6);
--shadow-glow: 0 0 20px rgba(232, 133, 26, 0.15);
/* Status colours */
--color-success: #22c55e;
--color-success-bg: rgba(34, 197, 94, 0.12);
--color-danger: #ef4444;
--color-danger-bg: rgba(239, 68, 68, 0.12);
--color-warning: #f59e0b;
--color-warning-bg: rgba(245, 158, 11, 0.12);
--color-info: #3b82f6;
--color-info-bg: rgba(59, 130, 246, 0.12);
/* Stat card accent colours */
--stat-1: #e8851a;
--stat-2: #22c55e;
--stat-3: #f59e0b;
--stat-4: #3b82f6;
/* Misc */
--radius-sm: 0.5rem;
--radius-md: 0.625rem;
--radius-lg: 0.875rem;
--radius-xl: 1.25rem;
--transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
--transition-normal: 250ms cubic-bezier(0.4, 0, 0.2, 1);
/* Layout dimensions */
--bottom-nav-height: 64px;
}
/* === LIGHT MODE === */
[data-theme="light"] {
--bs-body-color: #1a1a2e;
--bs-body-bg: #f4f4f8;
--bs-border-color: #e0e0e8;
/* Brand tweaks for light */
--accent: #d97706;
--accent-hover: #b45309;
--accent-subtle: rgba(217, 119, 6, 0.08);
--accent-text: #92400e;
--accent-glow: rgba(217, 119, 6, 0.15);
/* Surfaces */
--bg-body: #f4f4f8;
--bg-card: #ffffff;
--bg-card-hover: #fafafa;
--bg-elevated: #ffffff;
--bg-inset: #f0f0f5;
--bg-input: #ffffff;
--bg-nav: #1a1a2e;
--bg-sidebar: #1a1a2e;
/* Borders */
--border-default: #e0e0e8;
--border-subtle: #f0f0f5;
--border-strong: #c8c8d4;
--border-accent: rgba(217, 119, 6, 0.3);
/* Text */
--text-primary: #1a1a2e;
--text-secondary: #4a4a5a;
--text-tertiary: #8a8a9a;
--text-on-nav: #f0f0f0;
--text-on-nav-muted: #6b7280;
--text-link: #d97706;
/* Shadows */
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.06);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
--shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.1);
--shadow-xl: 0 20px 40px rgba(0, 0, 0, 0.12);
--shadow-glow: 0 0 20px rgba(217, 119, 6, 0.08);
/* Status colours */
--color-success: #16a34a;
--color-success-bg: #ecfdf5;
--color-danger: #dc2626;
--color-danger-bg: #fef2f2;
--color-warning: #d97706;
--color-warning-bg: #fffbeb;
--color-info: #2563eb;
--color-info-bg: #eff6ff;
}
/* ===================================================================
GLOBAL RESET & BASE STYLES
=================================================================== */
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
background-color: var(--bg-body);
color: var(--text-primary);
--bs-body-color: var(--text-primary);
--bs-body-bg: var(--bg-body);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
margin: 0;
padding: 0;
}
h1, h2, h3, h4, h5, h6 {
font-family: 'Poppins', sans-serif;
color: var(--text-primary);
font-weight: 600;
}
a {
color: var(--text-link);
transition: color var(--transition-fast);
}
a:hover {
color: var(--accent-hover);
}
/* ===================================================================
APP LAYOUT — top bar + main content area
=================================================================== */
/* Wrapper for the whole app (topbar + content stacked vertically) */
.app-layout {
display: flex;
flex-direction: column;
min-height: 100vh;
}
/* === TOP BAR (always visible — horizontal nav on desktop, brand-only on mobile) === */
.app-topbar {
background: var(--bg-sidebar);
border-bottom: 1px solid var(--border-default);
position: sticky;
top: 0;
z-index: 1030;
padding: 0 1rem;
}
/* Inner flexbox container for topbar items */
.topbar-inner {
display: flex;
align-items: center;
height: 52px;
gap: 0.75rem;
max-width: 1400px;
margin: 0 auto;
width: 100%;
}
/* Brand logo + text */
.topbar-brand {
display: flex;
align-items: center;
gap: 0.5rem;
text-decoration: none;
flex-shrink: 0;
}
.topbar-brand:hover {
text-decoration: none;
}
/* Bolt icon box (also reused on login page) */
.sidebar-brand__icon {
width: 30px;
height: 30px;
background: linear-gradient(135deg, #e8851a 0%, #f59e0b 100%);
border-radius: var(--radius-sm);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 0.85rem;
flex-shrink: 0;
}
.topbar-brand__text {
font-family: 'Poppins', sans-serif;
font-weight: 700;
font-size: 1.1rem;
color: var(--text-on-nav);
letter-spacing: -0.02em;
}
.topbar-brand__text span {
color: var(--accent);
}
/* Horizontal nav links in topbar — centred between brand and actions */
.topbar-nav {
display: flex;
align-items: center;
justify-content: center;
gap: 0.15rem;
flex: 1;
}
.topbar-nav__link {
display: flex;
align-items: center;
gap: 0.35rem;
padding: 0.4rem 0.7rem;
border-radius: var(--radius-sm);
color: var(--text-on-nav-muted);
font-size: 0.8rem;
font-weight: 500;
text-decoration: none;
transition: all var(--transition-fast);
white-space: nowrap;
}
.topbar-nav__link:hover {
color: var(--text-on-nav);
background: rgba(255, 255, 255, 0.06);
text-decoration: none;
}
.topbar-nav__link.active {
color: var(--accent);
background: rgba(232, 133, 26, 0.1);
font-weight: 600;
}
.topbar-nav__link i {
font-size: 0.8rem;
width: 1rem;
text-align: center;
}
/* Right side of topbar: theme toggle + user avatar + logout */
.topbar-actions {
display: flex;
align-items: center;
gap: 0.5rem;
flex-shrink: 0;
margin-left: auto;
}
/* User avatar + name in topbar */
.topbar-user {
display: flex;
align-items: center;
gap: 0.4rem;
}
.topbar-user__avatar {
width: 28px;
height: 28px;
border-radius: 50%;
background: var(--accent);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: 600;
font-size: 0.7rem;
flex-shrink: 0;
}
.topbar-user__name {
color: var(--text-on-nav);
font-size: 0.78rem;
font-weight: 500;
}
/* === MAIN CONTENT AREA === */
.app-main {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
/* NO position/z-index here — avoids trapping Bootstrap modals in a stacking context */
}
/* Decorative gradient glows — separate fixed element, not on .app-main */
.app-glow {
position: fixed;
inset: 0;
pointer-events: none;
z-index: 0;
overflow: hidden;
}
.app-glow::before {
content: '';
position: absolute;
top: -200px;
right: -100px;
width: 600px;
height: 600px;
background: radial-gradient(ellipse, var(--accent-glow) 0%, transparent 70%);
}
.app-glow::after {
content: '';
position: absolute;
bottom: -300px;
left: 0;
width: 500px;
height: 500px;
background: radial-gradient(ellipse, rgba(232, 133, 26, 0.06) 0%, transparent 70%);
}
/* === BOTTOM TAB BAR (mobile only) === */
.app-bottom-nav {
display: none; /* hidden on desktop */
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: var(--bg-nav);
border-top: 1px solid var(--border-default);
z-index: 1030;
padding: 0.25rem 0;
padding-bottom: calc(0.25rem + env(safe-area-inset-bottom, 0px));
}
.bottom-nav-inner {
display: flex;
justify-content: space-around;
align-items: center;
}
.bottom-nav__link {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.15rem;
padding: 0.4rem 0.75rem;
color: var(--text-on-nav-muted);
text-decoration: none;
font-size: 0.65rem;
font-weight: 500;
transition: color var(--transition-fast);
border-radius: var(--radius-sm);
min-width: 56px;
}
.bottom-nav__link i {
font-size: 1.15rem;
}
.bottom-nav__link:hover,
.bottom-nav__link.active {
color: var(--accent);
text-decoration: none;
}
.bottom-nav__link.active {
font-weight: 600;
}
/* Main content inner */
.app-content {
flex-grow: 1;
/* NO position/z-index — lets Bootstrap modals escape to body-level stacking */
}
/* Footer inside main content */
.app-footer {
padding: 1.25rem 0;
margin-top: auto;
border-top: 1px solid var(--border-default);
font-size: 0.8rem;
color: var(--text-tertiary);
}
/* === HAMBURGER BUTTON (mobile only — hidden on desktop via d-lg-none) === */
.hamburger-btn {
background: none;
border: none;
color: var(--text-on-nav);
font-size: 1.2rem;
padding: 0.35rem 0.5rem;
border-radius: var(--radius-sm);
cursor: pointer;
transition: all var(--transition-fast);
}
.hamburger-btn:hover {
color: var(--accent);
background: rgba(255, 255, 255, 0.06);
}
/* === MOBILE MENU (slides down from topbar when hamburger is tapped) === */
/* Fixed below the topbar so it stays visible regardless of scroll position */
.mobile-menu {
position: fixed;
top: 52px; /* matches topbar-inner height */
left: 0;
right: 0;
z-index: 1029; /* just below topbar (1030) */
background: var(--bg-sidebar);
border-bottom: 1px solid var(--border-default);
max-height: 0;
overflow: hidden;
transition: max-height 300ms ease, opacity 200ms ease;
opacity: 0;
box-shadow: var(--shadow-lg);
}
/* Open state — toggled by JS */
.mobile-menu.open {
max-height: calc(100vh - 52px); /* never taller than remaining screen */
opacity: 1;
overflow-y: auto;
}
.mobile-menu__nav {
display: flex;
flex-direction: column;
padding: 0.5rem 1rem;
gap: 0.15rem;
}
.mobile-menu__link {
display: flex;
align-items: center;
gap: 0.6rem;
padding: 0.65rem 0.75rem;
border-radius: var(--radius-sm);
color: var(--text-on-nav-muted);
font-size: 0.85rem;
font-weight: 500;
text-decoration: none;
transition: all var(--transition-fast);
}
.mobile-menu__link:hover {
color: var(--text-on-nav);
background: rgba(255, 255, 255, 0.06);
text-decoration: none;
}
.mobile-menu__link.active {
color: var(--accent);
background: rgba(232, 133, 26, 0.1);
font-weight: 600;
}
.mobile-menu__link i {
width: 1.25rem;
text-align: center;
font-size: 0.9rem;
}
.mobile-menu__footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.75rem 1rem;
border-top: 1px solid var(--border-default);
margin-top: 0.25rem;
}
/* Semi-transparent backdrop behind the menu — tapping it closes the menu */
.mobile-menu-backdrop {
display: none;
position: fixed;
inset: 0;
top: 52px;
background: rgba(0, 0, 0, 0.5);
z-index: 1028; /* below menu (1029) and topbar (1030) */
}
.mobile-menu-backdrop.open {
display: block;
}
/* === RESPONSIVE: Mobile layout === */
@media (max-width: 991.98px) {
/* Hide desktop nav links — hamburger menu handles navigation on mobile */
.topbar-nav {
display: none;
}
/* Hide user name on mobile — just show avatar */
.topbar-user__name {
display: none;
}
/* Bottom tab bar hidden — replaced by hamburger menu */
.app-bottom-nav {
display: none;
}
}
/* ===================================================================
CARDS — glass-morphism with subtle borders
=================================================================== */
.card {
background: var(--bg-card);
border: 1px solid var(--border-default);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-sm);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
transition: background-color var(--transition-normal),
border-color var(--transition-normal),
box-shadow var(--transition-normal);
}
.card:hover {
box-shadow: var(--shadow-md);
}
.card-header {
background: transparent;
border-bottom: 1px solid var(--border-default);
}
/* === STAT CARDS — with orange accent line on left === */
.stat-card {
background: var(--bg-card);
border: 1px solid var(--border-default);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-sm);
transition: all var(--transition-normal);
position: relative;
overflow: hidden;
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
/* Left accent bar instead of top */
.stat-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 3px;
background: var(--stat-accent, var(--accent));
}
.stat-card:hover {
box-shadow: var(--shadow-md);
border-color: var(--border-strong);
transform: translateY(-1px);
}
/* Per-card accent colours */
.stat-card--danger { --stat-accent: var(--color-danger); }
.stat-card--success { --stat-accent: var(--color-success); }
.stat-card--warning { --stat-accent: var(--color-warning); }
.stat-card--info { --stat-accent: var(--color-info); }
.stat-card--accent { --stat-accent: var(--accent); }
.stat-card--purple { --stat-accent: #8b5cf6; }
/* Stat card label */
.stat-label {
font-size: 0.7rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-secondary);
margin-bottom: 0.25rem;
}
/* Stat card value */
.stat-value {
font-size: 1.35rem;
font-weight: 700;
color: var(--text-primary);
font-family: 'Poppins', sans-serif;
}
/* Stat card icon circle */
.stat-icon {
width: 2.75rem;
height: 2.75rem;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.1rem;
flex-shrink: 0;
}
.stat-icon--danger { background: var(--color-danger-bg); color: var(--color-danger); }
.stat-icon--success { background: var(--color-success-bg); color: var(--color-success); }
.stat-icon--warning { background: var(--color-warning-bg); color: var(--color-warning); }
.stat-icon--info { background: var(--color-info-bg); color: var(--color-info); }
.stat-icon--accent { background: var(--accent-subtle); color: var(--accent); }
.stat-icon--purple { background: rgba(139, 92, 246, 0.1); color: #8b5cf6; }
/* ===================================================================
BUTTONS
=================================================================== */
.btn {
font-weight: 500;
font-size: 0.875rem;
border-radius: var(--radius-sm);
transition: all var(--transition-fast);
letter-spacing: 0.01em;
}
/* Primary accent button — orange */
.btn-accent {
background: linear-gradient(135deg, #e8851a 0%, #f59e0b 100%);
color: var(--text-on-accent);
font-weight: 600;
border: none;
box-shadow: 0 2px 8px rgba(232, 133, 26, 0.3);
}
.btn-accent:hover {
background: linear-gradient(135deg, #f59e0b 0%, #fbbf24 100%);
color: var(--text-on-accent);
box-shadow: 0 4px 16px rgba(232, 133, 26, 0.4);
transform: translateY(-1px);
}
.btn-accent:active {
transform: translateY(0);
box-shadow: 0 1px 4px rgba(232, 133, 26, 0.3);
}
/* btn-primary — dark slate in dark mode, darker slate in light mode */
.btn-primary {
background-color: #2a2d3a;
border-color: #3a3d4a;
color: #d8d8d8;
}
.btn-primary:hover,
.btn-primary:focus {
background-color: #353849;
border-color: #4a4d5a;
color: #ffffff;
}
.btn-primary:active,
.btn-primary.active {
background-color: #1e2130;
border-color: #3a3d4a;
color: #ffffff;
}
/* Light mode btn-primary — dark navy for good contrast */
[data-theme="light"] .btn-primary {
background-color: #1e293b;
border-color: #1e293b;
color: #ffffff;
}
[data-theme="light"] .btn-primary:hover,
[data-theme="light"] .btn-primary:focus {
background-color: #334155;
border-color: #334155;
color: #ffffff;
}
/* Dark mode outline button fixes */
[data-theme="dark"] .btn-outline-secondary,
:root .btn-outline-secondary {
color: var(--text-secondary);
border-color: var(--border-strong);
}
[data-theme="dark"] .btn-outline-secondary:hover,
:root .btn-outline-secondary:hover {
background-color: var(--bg-elevated);
color: var(--text-primary);
border-color: var(--text-secondary);
}
.btn-outline-info {
color: var(--color-info);
border-color: var(--color-info);
}
.btn-outline-warning {
color: var(--color-warning);
border-color: var(--color-warning);
}
.btn-outline-danger {
color: var(--color-danger);
border-color: var(--color-danger);
}
[data-theme="light"] .btn-outline-secondary {
color: var(--text-secondary);
border-color: var(--border-default);
}
[data-theme="light"] .btn-outline-secondary:hover {
background-color: var(--bg-inset);
color: var(--text-primary);
}
/* ===================================================================
TABLES — compact text for data-dense views
=================================================================== */
.table {
color: var(--text-primary);
--bs-table-bg: transparent;
--bs-table-color: var(--text-primary);
font-size: 0.78rem;
}
.table > thead {
background-color: var(--bg-inset);
}
.table-light {
--bs-table-bg: var(--bg-inset);
--bs-table-color: var(--text-secondary);
}
.table > tbody > tr {
border-color: var(--border-subtle);
transition: background-color var(--transition-fast);
}
.table-hover > tbody > tr:hover {
background-color: var(--bg-card-hover);
--bs-table-hover-bg: var(--bg-card-hover);
--bs-table-hover-color: var(--text-primary);
color: var(--text-primary);
}
.table th {
font-weight: 600;
font-size: 0.68rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-secondary);
border-bottom-width: 1px;
}
/* ===================================================================
FORMS
=================================================================== */
.form-control,
.form-select {
background-color: var(--bg-input);
border-color: var(--border-default);
color: var(--text-primary);
border-radius: var(--radius-sm);
transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
/* Placeholder text — visible but subtle */
.form-control::placeholder,
.form-select::placeholder {
color: var(--text-tertiary);
opacity: 1;
}
.form-control:focus,
.form-select:focus {
background-color: var(--bg-input);
border-color: var(--accent);
color: var(--text-primary);
box-shadow: 0 0 0 3px var(--accent-subtle);
}
.form-label {
font-weight: 500;
font-size: 0.875rem;
color: var(--text-secondary);
margin-bottom: 0.375rem;
}
/* === NATIVE DATE/MONTH PICKER ICONS (Chromium) ===
The browser paints a small calendar icon on the right of
<input type="date"> and <input type="month"> via the pseudo-element
::-webkit-calendar-picker-indicator. On dark backgrounds the default
black icon is nearly invisible. CSS can't set its fill directly, so
we use a filter chain to tint it toward our amber accent (#e8851a).
Firefox doesn't render this indicator so the rule is a no-op there. */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="month"]::-webkit-calendar-picker-indicator {
cursor: pointer;
opacity: 0.9;
filter: invert(58%) sepia(89%) saturate(862%) hue-rotate(357deg) brightness(93%) contrast(92%);
}
input[type="date"]::-webkit-calendar-picker-indicator:hover,
input[type="month"]::-webkit-calendar-picker-indicator:hover {
opacity: 1;
}
.form-check-input:checked {
background-color: var(--accent);
border-color: var(--accent);
}
/* === FORMSET ROW — MARKED FOR DELETION ===
When a user clicks the trash button on a certification/warning row,
JS adds `.row-marked-delete` to that row. These styles fade the row
and strike through its inputs so it's visually obvious the row will
be removed on save. The "Undo" link restores everything. */
.formset-row.row-marked-delete {
opacity: 0.55;
background: rgba(239, 68, 68, 0.06);
border-color: rgba(239, 68, 68, 0.3) !important;
}
.formset-row.row-marked-delete .form-control,
.formset-row.row-marked-delete .form-select,
.formset-row.row-marked-delete textarea {
text-decoration: line-through;
pointer-events: none; /* can't edit a row you're removing */
background: var(--bg-inset, #f0f0f5);
}
.formset-row.row-marked-delete .form-label {
text-decoration: line-through;
}
.input-group-text {
background-color: var(--bg-inset);
border-color: var(--border-default);
color: var(--text-secondary);
}
/* === BOOTSTRAP TOOLTIPS — themed for dark/light modes ===
Bootstrap 5.3's default tooltip uses `--bs-body-color` as background
and `--bs-body-bg` as text colour. In dark mode that produces a light
tooltip with dark text, which clashes with the rest of the UI and can
be unreadable when the body/bg values are very close.
Override the tooltip CSS variables to use our elevated-surface colours
(same palette as cards on hover) — readable on both dark and light. */
.tooltip {
--bs-tooltip-bg: var(--bg-card-hover);
--bs-tooltip-color: var(--text-primary);
--bs-tooltip-opacity: 1;
}
.tooltip .tooltip-inner {
border: 1px solid var(--border-default);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
font-size: 0.8rem;
max-width: 280px;
padding: 6px 10px;
font-weight: 500;
}
/* The arrow inherits its color from --bs-tooltip-bg automatically, but
we give it a matching border so it stays connected visually. */
/* ===================================================================
MODALS
=================================================================== */
.modal-content {
background-color: var(--bg-elevated);
border: 1px solid var(--border-default);
border-radius: var(--radius-xl);
box-shadow: var(--shadow-xl);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
.modal-header {
border-bottom: 1px solid var(--border-default);
padding: 1.25rem 1.5rem;
}
.modal-title {
font-size: 1.1rem;
font-weight: 600;
}
.modal-body {
padding: 1.5rem;
}
.modal-footer {
border-top: 1px solid var(--border-default);
padding: 1rem 1.5rem;
}
/* ===================================================================
BADGES (status indicators)
=================================================================== */
.badge {
font-weight: 500;
font-size: 0.7rem;
letter-spacing: 0.02em;
padding: 0.35em 0.65em;
border-radius: var(--radius-sm);
}
/* ===================================================================
NAV TABS (Payroll dashboard tabs)
=================================================================== */
.nav-tabs {
border-bottom: 2px solid var(--border-default);
}
.nav-tabs .nav-link {
color: var(--text-secondary);
font-weight: 500;
font-size: 0.875rem;
border: none;
border-bottom: 2px solid transparent;
margin-bottom: -2px;
padding: 0.75rem 1.25rem;
transition: all var(--transition-fast);
}
.nav-tabs .nav-link:hover {
color: var(--text-primary);
border-bottom-color: var(--border-strong);
background: none;
}
.nav-tabs .nav-link.active {
color: var(--accent);
border-bottom-color: var(--accent);
background: none;
font-weight: 600;
}
/* ===================================================================
THEME TOGGLE BUTTON (in topbar)
=================================================================== */
.theme-toggle {
background: rgba(255, 255, 255, 0.06);
border: 1px solid var(--border-default);
color: var(--text-on-nav-muted);
cursor: pointer;
padding: 0.4rem;
border-radius: var(--radius-sm);
font-size: 0.85rem;
transition: all var(--transition-fast);
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
}
.theme-toggle:hover {
color: var(--accent);
background: rgba(232, 133, 26, 0.1);
border-color: var(--accent);
}
/* ===================================================================
DASHBOARD HEADER — gradient banner with orange accents
=================================================================== */
.dashboard-header {
background: linear-gradient(135deg, #111318 0%, #1a1d26 50%, #2a1a0a 100%);
color: white;
padding: 2rem 2.5rem;
margin-bottom: -3rem;
border-radius: var(--radius-xl);
position: relative;
overflow: hidden;
border: 1px solid var(--border-default);
}
/* Orange glow decoration on dashboard header */
.dashboard-header::before {
content: '';
position: absolute;
top: -60%;
right: -15%;
width: 350px;
height: 350px;
background: radial-gradient(circle, rgba(232, 133, 26, 0.2) 0%, transparent 65%);
pointer-events: none;
}
.dashboard-header::after {
content: '';
position: absolute;
bottom: -40%;
left: 10%;
width: 200px;
height: 200px;
background: radial-gradient(circle, rgba(245, 158, 11, 0.1) 0%, transparent 70%);
pointer-events: none;
}
/* Light mode dashboard header */
[data-theme="light"] .dashboard-header {
background: linear-gradient(135deg, #1a1a2e 0%, #2d2d4a 50%, #3d2a10 100%);
}
/* ===================================================================
PAGE-LEVEL UTILITIES
=================================================================== */
.page-header {
margin-bottom: 1.5rem;
}
.page-title {
font-size: 1.5rem;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 0;
}
/* === PAYROLL ACTION BUTTONS — 2x2 grid on mobile, row on desktop === */
@media (max-width: 767.98px) {
.payroll-actions {
display: grid !important;
grid-template-columns: 1fr 1fr;
gap: 0.5rem;
width: 100%;
}
.payroll-actions .btn {
font-size: 0.75rem;
padding: 0.45rem 0.6rem;
white-space: nowrap;
}
}
/* On desktop, restore normal button size (undo btn-sm) */
@media (min-width: 768px) {
.btn-md-normal {
font-size: 0.875rem !important;
padding: 0.375rem 0.75rem !important;
}
}
.text-muted {
color: var(--text-secondary) !important;
}
.text-dark {
color: var(--text-primary) !important;
}
.border-bottom {
border-color: var(--border-default) !important;
}
/* ===================================================================
ALERTS
=================================================================== */
.alert {
border-radius: var(--radius-md);
border: none;
font-size: 0.875rem;
}
/* ===================================================================
FOOTER (inside app-main)
=================================================================== */
.footer {
background-color: transparent;
color: var(--text-tertiary);
padding: 1.25rem 0;
margin-top: auto;
border-top: 1px solid var(--border-default);
font-size: 0.8rem;
}
/* ===================================================================
SCROLLBAR (premium dark)
=================================================================== */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: var(--border-strong);
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--text-tertiary);
}
/* ===================================================================
QUICK ACTION CARD (dashboard)
=================================================================== */
.quick-action {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 1.25rem 1rem;
border-radius: var(--radius-lg);
border: 1px solid var(--border-default);
background: var(--bg-card);
color: var(--text-primary);
text-decoration: none;
transition: all var(--transition-fast);
flex: 1;
min-width: 120px;
}
.quick-action:hover {
background: var(--accent-subtle);
border-color: var(--accent);
color: var(--accent);
transform: translateY(-2px);
box-shadow: var(--shadow-glow);
text-decoration: none;
}
.quick-action i {
font-size: 1.5rem;
margin-bottom: 0.5rem;
color: var(--accent);
}
.quick-action span {
font-size: 0.8rem;
font-weight: 600;
}
/* ===================================================================
LIST GROUP (themed)
=================================================================== */
.list-group-item {
background-color: var(--bg-card);
border-color: var(--border-subtle);
color: var(--text-primary);
transition: background-color var(--transition-normal);
}
.list-group-item:hover {
background-color: var(--bg-card-hover);
}
/* ===================================================================
RESOURCE TOGGLE PANEL (dashboard)
=================================================================== */
.resource-hidden { display: none !important; }
.resource-row {
border-color: var(--border-subtle) !important;
transition: background-color var(--transition-fast);
}
.resource-row:hover {
background-color: var(--bg-card-hover);
}
/* ===================================================================
WORKER LOOKUP LINK (clickable names)
=================================================================== */
.worker-lookup-link {
color: var(--text-primary) !important;
text-decoration: none !important;
border-bottom: 1px dashed var(--border-strong);
transition: all var(--transition-fast);
}
.worker-lookup-link:hover {
color: var(--accent) !important;
border-bottom-color: var(--accent);
}
/* ===================================================================
CALENDAR VIEW (work history)
=================================================================== */
.cal-day {
min-height: 90px;
padding: 6px 8px;
border: 1px solid var(--border-default);
border-radius: var(--radius-sm);
background: var(--bg-card);
transition: all var(--transition-fast);
cursor: default;
}
.cal-day--other {
opacity: 0.4;
background: var(--bg-inset);
}
.cal-day--today {
border-color: var(--accent);
border-width: 2px;
}
.cal-day--today .cal-day__number {
color: var(--accent);
font-weight: 700;
}
.cal-day--has-logs {
cursor: pointer;
}
.cal-day--has-logs:hover {
background: var(--accent-subtle);
border-color: var(--accent);
box-shadow: var(--shadow-sm);
}
.cal-day--selected {
background: var(--accent-subtle);
border-color: var(--accent);
border-width: 2px;
box-shadow: 0 0 0 3px var(--accent-subtle);
}
.cal-day__number {
font-size: 0.85rem;
font-weight: 500;
color: var(--text-primary);
}
.cal-entry {
font-size: 0.72rem;
line-height: 1.3;
color: var(--text-secondary);
}
@media (max-width: 767.98px) {
.cal-day { min-height: 55px; padding: 4px; }
.cal-entry { display: none; }
}
/* ===================================================================
DARK MODE — Bootstrap utility overrides
Bootstrap's utility classes (.text-dark, .bg-warning, .table-light,
.form-control:disabled, etc.) use hardcoded colours that look wrong
on dark backgrounds. These overrides fix contrast issues.
=================================================================== */
/* .text-dark — Bootstrap uses #212529, unreadable on dark bg */
:root .text-dark,
:root .text-dark.ms-1 {
color: var(--text-primary) !important;
}
/* Loan badge: yellow bg + dark text for contrast */
.badge.bg-warning {
color: #000 !important;
}
/* table-light (used in thead) — fix for dark mode */
:root .table-light {
--bs-table-bg: var(--bg-inset);
--bs-table-color: var(--text-secondary);
--bs-table-border-color: var(--border-default);
}
[data-theme="light"] .table-light {
--bs-table-bg: #f0f0f5;
--bs-table-color: #4a4a5a;
}
/* Disabled form controls — visible text in dark mode */
.form-control:disabled,
.form-select:disabled {
background-color: var(--bg-inset);
color: var(--text-secondary);
opacity: 0.7;
border-color: var(--border-default);
}
/* form-select option dropdown — ensure readable in dark mode */
.form-select option {
background-color: var(--bg-card);
color: var(--text-primary);
}
/* btn-close — visible X button on dark backgrounds */
:root .btn-close {
filter: invert(1) grayscale(100%) brightness(200%);
}
[data-theme="light"] .btn-close {
filter: none;
}
/* Bootstrap text utilities that clash with dark mode */
:root .text-primary {
color: var(--color-info) !important;
}
:root .text-success {
color: var(--color-success) !important;
}
:root .text-danger {
color: var(--color-danger) !important;
}
:root .text-warning {
color: var(--color-warning) !important;
}
:root .text-info {
color: var(--color-info) !important;
}
:root .text-muted {
color: var(--text-secondary) !important;
}
/* btn-secondary in modals — visible in dark mode */
.btn-secondary {
background-color: var(--bg-elevated);
border-color: var(--border-strong);
color: var(--text-primary);
}
.btn-secondary:hover {
background-color: var(--border-default);
border-color: var(--border-strong);
color: var(--text-primary);
}
/* ===================================================================
PRINT STYLES — ensure payslips print as black text on white page
=================================================================== */
@media print {
/* Override ALL CSS variables to light/print-friendly values */
:root, [data-theme="dark"], [data-theme="light"] {
--bg-body: #ffffff !important;
--bg-card: #ffffff !important;
--bg-card-hover: #ffffff !important;
--bg-elevated: #ffffff !important;
--bg-inset: #f5f5f5 !important;
--bg-input: #ffffff !important;
--text-primary: #000000 !important;
--text-secondary: #333333 !important;
--text-tertiary: #666666 !important;
--text-on-accent: #000000 !important;
--text-link: #000000 !important;
--border-default: #cccccc !important;
--border-subtle: #dddddd !important;
--border-strong: #999999 !important;
--accent: #d97706 !important;
--color-success: #16a34a !important;
--color-danger: #dc2626 !important;
--color-warning: #d97706 !important;
--color-info: #2563eb !important;
--color-success-bg: #ecfdf5 !important;
--color-danger-bg: #fef2f2 !important;
--color-warning-bg: #fffbeb !important;
--color-info-bg: #eff6ff !important;
--bs-body-color: #000000 !important;
--bs-body-bg: #ffffff !important;
}
body {
background: white !important;
color: black !important;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
/* Hide navigation and non-print elements */
.app-topbar, .app-bottom-nav,
.app-footer, .app-glow, .d-print-none { display: none !important; }
/* Cards: clean white with thin border, no blur */
.card {
background: white !important;
border: 1px solid #ddd !important;
box-shadow: none !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
}
/* Stat cards: remove glass effect */
.stat-card {
background: white !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
box-shadow: none !important;
}
/* Tables: black text on white */
.table, .table th, .table td {
color: #000 !important;
background: white !important;
border-color: #ccc !important;
font-size: 11pt !important;
}
.table > thead, .table-light {
background-color: #f0f0f0 !important;
}
/* Headings and text: all black */
h1, h2, h3, h4, h5, h6, p, span, div, td, th, a {
color: #000 !important;
}
/* Badges: print-friendly */
.badge {
border: 1px solid #999 !important;
background: #f5f5f5 !important;
color: #000 !important;
}
/* Ensure the stat-label text prints as dark grey */
.stat-label {
color: #555 !important;
}
/* Links: no colour, no underline */
a { color: #000 !important; text-decoration: none !important; }
}
/* ===================================================================
SMOOTH TRANSITIONS for theme switch
=================================================================== */
body, .card, .modal-content, .form-control, .form-select,
.table, .btn, .alert, .badge,
.input-group-text, .stat-card, .cal-day,
.app-topbar, .app-bottom-nav {
transition: background-color var(--transition-normal),
color var(--transition-normal),
border-color var(--transition-normal),
box-shadow var(--transition-normal);
}
/* === Work log payroll: clickable row hover === */
/* Applied only by base.html / templates that add class="work-log-row" */
/* (admin-only; supervisors never get the class so hover doesn't apply). */
.work-log-row {
transition: background-color 120ms ease-in-out;
}
.work-log-row:hover td {
background: var(--bg-card-hover);
}
/* === Report filter pills === */
.filter-pill {
display: inline-flex;
align-items: center;
padding: 0.35rem 0.75rem;
font-size: 0.825rem;
background: var(--bg-inset);
color: var(--text-primary);
border: 1px solid var(--border-default);
border-radius: 999px;
line-height: 1.2;
}
.filter-pill i {
color: var(--accent);
font-size: 0.75rem;
}
.filter-pill__x {
margin-left: 0.5rem;
padding: 0 0.35rem;
color: var(--text-tertiary);
text-decoration: none;
font-weight: 600;
border-radius: 50%;
transition: color 120ms, background-color 120ms;
}
.filter-pill__x:hover {
color: var(--text-primary);
background: var(--bg-card-hover);
text-decoration: none;
}
/* === Choices.js theme overrides (dark + light, executive report modal) === */
/*
Choices.js ships with a white-bg, light-grey-text default that clashes with
the app's dark theme. These overrides replace those defaults with the app's
own design tokens so the multi-select picker matches every other card and
input on the page. All tokens auto-switch between dark (:root) and light
(:root.light) themes — no duplicate blocks needed.
Specificity note: the Choices.js CDN CSS loads AFTER custom.css (inside the
modal partial, near </body>). Every rule below chains the root `.choices`
class to beat the CDN's same-class selectors, and uses !important on the
two properties Choices.js hardcodes most aggressively (color + background)
so dark/light theme tokens always win.
*/
/* Container — the outer wrapper that replaces the native <select> */
.choices.choices {
margin-bottom: 0;
}
/* Closed-state input area (where chips and the placeholder/search sit) */
.choices .choices__inner {
background: var(--bg-inset) !important;
color: var(--text-primary) !important;
border: 1px solid var(--border-default) !important;
border-radius: 0.5rem;
padding: 0.4rem 0.55rem;
min-height: 2.55rem;
font-size: 0.925rem;
}
.choices.is-focused .choices__inner,
.choices.is-open .choices__inner {
border-color: var(--accent) !important;
box-shadow: 0 0 0 0.15rem rgba(232, 133, 26, 0.18);
}
/* The cloned search input typed into when the dropdown is open */
.choices .choices__input {
background: transparent !important;
color: var(--text-primary) !important;
font-size: 0.925rem;
}
.choices .choices__input::placeholder {
color: var(--text-tertiary) !important;
}
/* Dropdown popup — the list of choices */
.choices .choices__list--dropdown,
.choices .choices__list[aria-expanded] {
background: var(--bg-card) !important;
border: 1px solid var(--border-default) !important;
border-radius: 0.5rem;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
margin-top: 4px;
z-index: 2000;
color: var(--text-primary) !important;
}
/* Individual option rows in the dropdown — default state */
.choices .choices__list--dropdown .choices__item,
.choices .choices__list[aria-expanded] .choices__item {
color: var(--text-primary) !important;
background: transparent !important;
padding: 0.5rem 0.75rem;
font-size: 0.9rem;
}
/* Hovered / keyboard-highlighted option — matches the "Month button selected" look */
.choices .choices__list--dropdown .choices__item--selectable.is-highlighted,
.choices .choices__list[aria-expanded] .choices__item--selectable.is-highlighted {
background: var(--bg-card-hover) !important;
color: var(--text-primary) !important;
}
/* The trailing "Press to select" hint */
.choices .choices__list--dropdown .choices__item--selectable.is-highlighted::after,
.choices .choices__list[aria-expanded] .choices__item--selectable.is-highlighted::after {
color: var(--accent);
opacity: 0.9;
}
/* Disabled / placeholder-style rows (e.g. "No matches found") */
.choices .choices__list--dropdown .choices__item--disabled,
.choices .choices__list[aria-expanded] .choices__item--disabled {
color: var(--text-tertiary) !important;
}
/* Placeholder text in the input area when nothing is selected */
.choices .choices__placeholder {
color: var(--text-tertiary) !important;
opacity: 1;
}
/* Selected chips in multi-select mode (visible when items are chosen) */
.choices .choices__list--multiple .choices__item {
background: var(--accent) !important;
border: 1px solid var(--accent) !important;
color: #fff !important;
font-size: 0.82rem;
font-weight: 500;
padding: 0.2rem 0.6rem;
margin: 0.15rem 0.25rem 0.15rem 0;
border-radius: 999px;
}
.choices .choices__list--multiple .choices__item.is-highlighted {
background: var(--accent-hover) !important;
border-color: var(--accent-hover) !important;
}
/* The × button on each selected chip */
.choices .choices__list--multiple .choices__button {
border-left: 1px solid rgba(255, 255, 255, 0.4);
margin: 0 0 0 0.5rem;
padding-left: 0.5rem;
opacity: 0.85;
}
.choices .choices__list--multiple .choices__button:hover {
opacity: 1;
}
/* No-results / no-choices message */
.choices .choices__list .choices__item--no-results,
.choices .choices__list .choices__item--no-choices {
color: var(--text-tertiary) !important;
font-style: italic;
background: transparent !important;
}
/* === Hero KPI card variant (executive report) === */
/*
A larger, more typographic version of the existing .stat-card,
used for the top-of-report KPI band. Keeps the same --accent-based
colour stripes (stat-card--danger, --warning, --info) but scales
the number, flattens the label to uppercase tracked caps, and adds
a subtle tertiary sub-line for context like "as of 15:42" or the
date range.
*/
.stat-card--hero {
padding: 1.25rem 1.4rem;
min-height: 130px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.stat-card--hero .stat-label {
font-size: 0.7rem;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--text-tertiary);
margin-bottom: 0.4rem;
}
.stat-card--hero .stat-value {
font-family: 'Poppins', sans-serif;
font-weight: 600;
font-size: 1.85rem;
line-height: 1;
color: var(--text-primary);
font-variant-numeric: tabular-nums;
}
.stat-card--hero .stat-subline {
font-size: 0.78rem;
color: var(--text-tertiary);
margin-top: 0.6rem;
}
/* === Report chapter headings === */
/*
Numbered chapter markers (I, II, III, IV) on the executive report.
Each heading has an orange filled circle with the Roman numeral
followed by the chapter title. Used on Chapter I (Lifetime Context),
II (Selected Period), III (Worker Breakdown), IV (Team x Project).
*/
.chapter-heading {
display: flex;
align-items: center;
gap: 0.75rem;
color: var(--text-primary);
font-family: 'Poppins', sans-serif;
font-weight: 600;
}
.chapter-heading .chapter-num {
display: inline-flex;
align-items: center;
justify-content: center;
width: 1.85rem;
height: 1.85rem;
border-radius: 50%;
background: var(--accent);
color: #fff;
font-size: 0.85rem;
font-weight: 700;
font-family: 'Inter', sans-serif;
}
/* tabular-nums for all numeric report tables */
.report-numeric td,
.report-numeric th {
font-variant-numeric: tabular-nums;
}
/* === Pivot-table footer totals (Chapter IV) === */
/*
Bold, slightly-lifted row at the bottom of the Team × Project pivot
that holds the column totals + grand total. The 2px top border
visually separates totals from the data rows; the inset background
is the same --bg-inset used by other "slightly raised" surfaces.
*/
.table-total-row td {
border-top: 2px solid var(--border-default) !important;
background: var(--bg-inset);
}
/* === Inline Filters (pill-as-dropdown) on the report page === */
/*
Layered on top of the existing .filter-pill rules (lines ~14961524).
Five components:
1. .filter-pill--editable: pointer cursor, hover tint, chevron
2. .filter-pill--dirty: accent outline + small pulsing dot when uncommitted
3. .filter-popover: absolute-positioned dropdown beneath the pill
4. .apply-filters-group: slide-in Apply/Reset buttons when any pill dirty
5. .filter-toast-container: cross-filter auto-removal notices
*/
/* --- Wrapper keeps the popover anchored to its pill --- */
.filter-pill-wrap {
display: inline-flex;
align-items: center;
}
/* --- Editable pill: button, cursor, hover state, chevron --- */
.filter-pill--editable {
cursor: pointer;
border: 1px solid var(--border-default);
background: var(--bg-inset);
color: var(--text-primary);
transition: background-color 120ms, border-color 120ms, box-shadow 120ms;
}
.filter-pill--editable:hover {
background: var(--bg-card-hover);
border-color: var(--accent);
}
.filter-pill--editable[aria-expanded="true"] {
background: var(--bg-card-hover);
border-color: var(--accent);
}
.filter-pill__chevron {
opacity: 0.7;
transition: transform 120ms;
}
.filter-pill--editable[aria-expanded="true"] .filter-pill__chevron {
transform: rotate(180deg);
}
/* --- Dirty state: pulsing accent dot + outline --- */
.filter-pill--dirty {
border-color: var(--accent);
box-shadow: 0 0 0 2px rgba(232, 133, 26, 0.18);
}
.filter-pill--dirty::before {
content: '';
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--accent);
margin-right: 0.4rem;
animation: filter-pill-pulse 1.4s ease-in-out infinite;
}
@keyframes filter-pill-pulse {
0%, 100% { opacity: 0.55; }
50% { opacity: 1; }
}
/* --- Popover positioned under the pill --- */
.filter-popover {
position: absolute;
top: calc(100% + 6px);
left: 0;
z-index: 1040; /* below Bootstrap modal (1055) but above everything else */
min-width: 300px;
max-width: 420px;
background: var(--bg-card);
border: 1px solid var(--border-default);
border-radius: 0.5rem;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
padding: 0;
}
.filter-popover[hidden] {
display: none;
}
.filter-popover__body {
padding: 1rem;
}
.filter-popover__footer {
display: flex;
justify-content: flex-end;
gap: 0.5rem;
padding: 0.6rem 1rem;
border-top: 1px solid var(--border-default);
background: var(--bg-inset);
border-radius: 0 0 0.5rem 0.5rem;
}
/* --- Mobile: popovers stretch full-width below the pill strip --- */
@media (max-width: 576px) {
.filter-popover {
position: fixed;
top: auto;
bottom: 0;
left: 0;
right: 0;
width: 100vw;
max-width: 100vw;
border-radius: 0.5rem 0.5rem 0 0;
z-index: 1050;
}
}
/* --- Apply / Reset button group --- */
.apply-filters-group {
display: flex;
align-items: center;
animation: apply-slide-in 180ms ease-out;
}
.apply-filters-group[hidden] {
display: none;
}
@keyframes apply-slide-in {
from { opacity: 0; transform: translateX(8px); }
to { opacity: 1; transform: translateX(0); }
}
/* --- Toast container for cross-filter auto-remove notices --- */
.filter-toast-container {
position: fixed;
top: 4.5rem; /* below topbar */
right: 1rem;
z-index: 1060;
display: flex;
flex-direction: column;
gap: 0.5rem;
pointer-events: none;
max-width: 320px;
}
.filter-toast {
background: var(--bg-card);
color: var(--text-primary);
border: 1px solid var(--accent);
border-left: 4px solid var(--accent);
border-radius: 0.375rem;
padding: 0.75rem 1rem;
font-size: 0.875rem;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.22);
animation: filter-toast-in 200ms ease-out;
pointer-events: auto;
}
.filter-toast--exiting {
animation: filter-toast-out 200ms ease-in forwards;
}
@keyframes filter-toast-in {
from { opacity: 0; transform: translateX(12px); }
to { opacity: 1; transform: translateX(0); }
}
@keyframes filter-toast-out {
to { opacity: 0; transform: translateX(12px); }
}