diff --git a/staticfiles/css/custom.css b/staticfiles/css/custom.css index 108056f..283e9a5 100644 --- a/staticfiles/css/custom.css +++ b/staticfiles/css/custom.css @@ -1,21 +1,1483 @@ +/* =================================================================== + 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 { - --bg-color-start: #6a11cb; - --bg-color-end: #2575fc; - --text-color: #ffffff; - --card-bg-color: rgba(255, 255, 255, 0.01); - --card-border-color: rgba(255, 255, 255, 0.1); + /* 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; - font-family: 'Inter', sans-serif; - background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end)); - color: var(--text-color); - display: flex; - justify-content: center; - align-items: center; - min-height: 100vh; - text-align: center; - overflow: hidden; - position: relative; + 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 + and 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); }