From 3c3faf13d46124441132fca1c4fbbc314960469a Mon Sep 17 00:00:00 2001 From: Dries Peeters Date: Fri, 17 Oct 2025 11:51:36 +0200 Subject: [PATCH 1/4] feat: Implement Tailwind CSS UI redesign across application Migrate frontend from custom CSS to Tailwind CSS framework with comprehensive template updates and improved component structure. Breaking Changes: - Remove legacy CSS files (base.css, calendar.css, ui.css, etc.) - Replace with Tailwind-based styling system New Features: - Add Tailwind CSS configuration with PostCSS pipeline - Create new template components for admin, clients, invoices, projects, reports - Add form-bridge.css for smooth transition between legacy and Tailwind styles - Add default avatar SVG asset - Implement Tailwind-based kanban board template - Add comprehensive UI quick wins documentation Infrastructure: - Add package.json with Tailwind dependencies - Configure PostCSS and Tailwind build pipeline - Update .gitignore for Node modules and build artifacts Testing: - Add template rendering tests (test_tasks_templates.py) - Add UI component tests (test_ui_quick_wins.py) Templates Added: - Admin: dashboard, settings, system info, user management - Clients: list and detail views - Invoices: full CRUD templates with payment recording - Projects: list, detail, and Tailwind kanban views - Reports: comprehensive reporting templates - Timer: manual entry interface This commit represents the first phase of the UI redesign initiative, maintaining backward compatibility where needed while establishing the foundation for modern, responsive interfaces. --- .gitignore | 9 +- Dockerfile | 14 + IMPLEMENTATION_SUMMARY.md | 1 + app/__init__.py | 2 +- app/routes/auth.py | 14 +- app/routes/kanban.py | 23 + app/routes/main.py | 24 +- app/static/base.css | 5144 ----------------- app/static/calendar.css | 706 --- app/static/commands.js | 47 +- app/static/empty-states.css | 478 -- app/static/enhanced-search.css | 483 -- app/static/enhanced-search.js | 16 +- app/static/enhanced-tables.css | 552 -- app/static/form-bridge.css | 129 + app/static/images/avatar-default.svg | 15 + app/static/keyboard-shortcuts.css | 421 -- app/static/loading-states.css | 435 -- app/static/micro-interactions.css | 586 -- app/static/mobile.css | 1296 ----- app/static/reports.css | 679 --- app/static/src/input.css | 34 + app/static/theme-template.css | 504 -- app/static/toast-notifications.css | 368 +- app/static/toast-notifications.js | 2 +- app/static/ui.css | 87 - app/templates/admin/dashboard.html | 55 + app/templates/admin/settings.html | 56 + app/templates/admin/system_info.html | 19 + app/templates/admin/user_form.html | 41 + app/templates/admin/users.html | 44 + .../analytics/dashboard_improved.html | 1017 +--- app/templates/auth/edit_profile.html | 92 +- app/templates/auth/login.html | 839 +-- app/templates/auth/profile.html | 127 +- app/templates/base.html | 1198 ++-- app/templates/clients/list.html | 75 + app/templates/clients/view.html | 73 + app/templates/components/cards.html | 14 + app/templates/invoices/create.html | 47 + app/templates/invoices/edit.html | 69 + app/templates/invoices/list.html | 47 + app/templates/invoices/record_payment.html | 30 + app/templates/invoices/view.html | 70 + app/templates/kanban/board.html | 171 + app/templates/kanban/columns.html | 214 +- app/templates/kanban/create_column.html | 179 +- app/templates/kanban/edit_column.html | 236 +- app/templates/main/dashboard.html | 744 +-- app/templates/projects/_kanban_tailwind.html | 86 + app/templates/projects/list.html | 112 + app/templates/projects/view.html | 115 + app/templates/reports/index.html | 52 + app/templates/reports/project_report.html | 68 + app/templates/reports/summary.html | 38 + app/templates/reports/task_report.html | 68 + app/templates/reports/user_report.html | 66 + app/templates/tasks/create.html | 371 +- app/templates/tasks/edit.html | 345 +- app/templates/tasks/list.html | 466 +- app/templates/tasks/view.html | 948 +-- app/templates/timer/manual_entry.html | 136 + docs/QUICK_WINS_UI.md | 25 + package.json | 24 + postcss.config.js | 6 + setup.py | 2 +- tailwind.config.js | 27 + templates/admin/oidc_debug.html | 620 +- templates/admin/oidc_user_detail.html | 284 +- templates/clients/create.html | 194 +- templates/clients/edit.html | 226 +- templates/main/about.html | 510 +- templates/main/help.html | 1059 ++-- templates/projects/create.html | 366 +- templates/projects/edit.html | 182 +- tests/test_analytics.py | 29 + tests/test_routes.py | 33 +- tests/test_tasks_templates.py | 71 + tests/test_ui_quick_wins.py | 36 + 79 files changed, 5129 insertions(+), 18962 deletions(-) delete mode 100644 app/static/base.css delete mode 100644 app/static/calendar.css delete mode 100644 app/static/empty-states.css delete mode 100644 app/static/enhanced-search.css delete mode 100644 app/static/enhanced-tables.css create mode 100644 app/static/form-bridge.css create mode 100644 app/static/images/avatar-default.svg delete mode 100644 app/static/keyboard-shortcuts.css delete mode 100644 app/static/loading-states.css delete mode 100644 app/static/micro-interactions.css delete mode 100644 app/static/mobile.css delete mode 100644 app/static/reports.css create mode 100644 app/static/src/input.css delete mode 100644 app/static/theme-template.css delete mode 100644 app/static/ui.css create mode 100644 app/templates/admin/dashboard.html create mode 100644 app/templates/admin/settings.html create mode 100644 app/templates/admin/system_info.html create mode 100644 app/templates/admin/user_form.html create mode 100644 app/templates/admin/users.html create mode 100644 app/templates/clients/list.html create mode 100644 app/templates/clients/view.html create mode 100644 app/templates/components/cards.html create mode 100644 app/templates/invoices/create.html create mode 100644 app/templates/invoices/edit.html create mode 100644 app/templates/invoices/list.html create mode 100644 app/templates/invoices/record_payment.html create mode 100644 app/templates/invoices/view.html create mode 100644 app/templates/kanban/board.html create mode 100644 app/templates/projects/_kanban_tailwind.html create mode 100644 app/templates/projects/list.html create mode 100644 app/templates/projects/view.html create mode 100644 app/templates/reports/index.html create mode 100644 app/templates/reports/project_report.html create mode 100644 app/templates/reports/summary.html create mode 100644 app/templates/reports/task_report.html create mode 100644 app/templates/reports/user_report.html create mode 100644 app/templates/timer/manual_entry.html create mode 100644 docs/QUICK_WINS_UI.md create mode 100644 package.json create mode 100644 postcss.config.js create mode 100644 tailwind.config.js create mode 100644 tests/test_tasks_templates.py create mode 100644 tests/test_ui_quick_wins.py diff --git a/.gitignore b/.gitignore index d91f288..0c6ff02 100644 --- a/.gitignore +++ b/.gitignore @@ -185,4 +185,11 @@ nginx/ssl/*.crt # docker-compose.https.yml is now tracked # Environment backups -.env.backup \ No newline at end of file +.env.backup + +# Node.js / Frontend build +node_modules/ +package-lock.json + +# Tailwind CSS build output (keep source in git) +app/static/dist/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 889ee37..6b37dc9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,14 @@ # syntax=docker/dockerfile:1.4 + +# --- Stage 1: Frontend Build --- +FROM node:18-slim as frontend +WORKDIR /app +COPY package*.json ./ +RUN npm install +COPY . . +RUN npm run build:docker + +# --- Stage 2: Python Application --- FROM python:3.11-slim-bullseye # Build-time version argument with safe default @@ -58,6 +68,9 @@ RUN --mount=type=cache,target=/root/.cache/pip \ # Copy project files COPY . . +# Copy compiled assets from frontend stage (overwriting the stale one from COPY .) +COPY --from=frontend /app/app/static/dist/output.css /app/app/static/dist/output.css + # Create all directories and set permissions in a single layer RUN mkdir -p \ /app/translations \ @@ -122,3 +135,4 @@ ENTRYPOINT ["/app/docker/entrypoint_fixed.sh"] # Run the application CMD ["python", "/app/start.py"] + diff --git a/IMPLEMENTATION_SUMMARY.md b/IMPLEMENTATION_SUMMARY.md index e6ec201..ba9cc07 100644 --- a/IMPLEMENTATION_SUMMARY.md +++ b/IMPLEMENTATION_SUMMARY.md @@ -55,6 +55,7 @@ Successfully implemented custom kanban board columns functionality for the TimeT ### Documentation - `KANBAN_CUSTOMIZATION.md` - Comprehensive feature documentation - `IMPLEMENTATION_SUMMARY.md` - This file + - UI polish: Task create/edit pages tips redesigned; unified dark-mode handling for editor ## Files Modified diff --git a/app/__init__.py b/app/__init__.py index 0222696..3dcb6cb 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -258,7 +258,7 @@ def create_app(config=None): "img-src 'self' data: https:; " "style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://fonts.googleapis.com https://cdn.datatables.net; " "font-src 'self' https://fonts.gstatic.com https://cdnjs.cloudflare.com data:; " - "script-src 'self' 'unsafe-inline' https://code.jquery.com https://cdn.datatables.net https://cdnjs.cloudflare.com https://cdn.jsdelivr.net; " + "script-src 'self' 'unsafe-inline' https://code.jquery.com https://cdn.datatables.net https://cdnjs.cloudflare.com https://cdn.jsdelivr.net https://esm.sh; " "connect-src 'self' ws: wss:; " "frame-ancestors 'none'" ) diff --git a/app/routes/auth.py b/app/routes/auth.py index 4843960..2ba2504 100644 --- a/app/routes/auth.py +++ b/app/routes/auth.py @@ -40,7 +40,7 @@ def login(): if not username: flash(_('Username is required'), 'error') - return render_template('auth/login.html') + return render_template('auth/login.html', allow_self_register=Config.ALLOW_SELF_REGISTER, auth_method=auth_method) # Normalize admin usernames from config try: @@ -62,12 +62,12 @@ def login(): if not safe_commit('self_register_user', {'username': username}): current_app.logger.error("Self-registration failed for '%s' due to DB error", username) flash(_('Could not create your account due to a database error. Please try again later.'), 'error') - return render_template('auth/login.html') + return render_template('auth/login.html', allow_self_register=Config.ALLOW_SELF_REGISTER, auth_method=auth_method) current_app.logger.info("Created new user '%s'", username) flash(_('Welcome! Your account has been created.'), 'success') else: flash(_('User not found. Please contact an administrator.'), 'error') - return render_template('auth/login.html') + return render_template('auth/login.html', allow_self_register=Config.ALLOW_SELF_REGISTER, auth_method=auth_method) else: # If existing user matches admin usernames, ensure admin role if username in admin_usernames and user.role != 'admin': @@ -75,12 +75,12 @@ def login(): if not safe_commit('promote_admin_user', {'username': username}): current_app.logger.error("Failed to promote '%s' to admin due to DB error", username) flash(_('Could not update your account role due to a database error.'), 'error') - return render_template('auth/login.html') + return render_template('auth/login.html', allow_self_register=Config.ALLOW_SELF_REGISTER, auth_method=auth_method) # Check if user is active if not user.is_active: flash(_('Account is disabled. Please contact an administrator.'), 'error') - return render_template('auth/login.html') + return render_template('auth/login.html', allow_self_register=Config.ALLOW_SELF_REGISTER, auth_method=auth_method) # Log in the user login_user(user, remember=True) @@ -98,9 +98,9 @@ def login(): except Exception as e: current_app.logger.exception("Login error: %s", e) flash(_('Unexpected error during login. Please try again or check server logs.'), 'error') - return render_template('auth/login.html') + return render_template('auth/login.html', allow_self_register=Config.ALLOW_SELF_REGISTER, auth_method=auth_method) - return render_template('auth/login.html') + return render_template('auth/login.html', allow_self_register=Config.ALLOW_SELF_REGISTER, auth_method=auth_method) @auth_bp.route('/logout') @login_required diff --git a/app/routes/kanban.py b/app/routes/kanban.py index 1415de1..ec72a1b 100644 --- a/app/routes/kanban.py +++ b/app/routes/kanban.py @@ -7,6 +7,29 @@ from app.utils.db import safe_commit from app.routes.admin import admin_required kanban_bp = Blueprint('kanban', __name__) +@kanban_bp.route('/kanban') +@login_required +def board(): + """Kanban board page with optional project filter""" + project_id = request.args.get('project_id', type=int) + query = Task.query + if project_id: + query = query.filter_by(project_id=project_id) + # Order tasks for stable rendering + tasks = query.order_by(Task.priority.desc(), Task.due_date.asc(), Task.created_at.asc()).all() + # Fresh columns + db.session.expire_all() + columns = KanbanColumn.get_active_columns() + # Provide projects for filter dropdown + from app.models import Project + projects = Project.query.filter_by(status='active').order_by(Project.name).all() + # No-cache + response = render_template('kanban/board.html', tasks=tasks, kanban_columns=columns, projects=projects, project_id=project_id) + resp = make_response(response) + resp.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate, max-age=0' + resp.headers['Pragma'] = 'no-cache' + resp.headers['Expires'] = '0' + return resp @kanban_bp.route('/kanban/columns') @login_required diff --git a/app/routes/main.py b/app/routes/main.py index 6dd62bb..872290e 100644 --- a/app/routes/main.py +++ b/app/routes/main.py @@ -46,13 +46,35 @@ def dashboard(): user_id=current_user.id ) + # Build Top Projects (last 30 days) based on user's activity + period_start = today - timedelta(days=30) + entries_30 = TimeEntry.query.filter( + TimeEntry.end_time.isnot(None), + TimeEntry.start_time >= period_start, + TimeEntry.user_id == current_user.id + ).all() + project_hours = {} + for e in entries_30: + if not e.project: + continue + project_hours.setdefault(e.project.id, { + 'project': e.project, + 'hours': 0.0, + 'billable_hours': 0.0 + }) + project_hours[e.project.id]['hours'] += e.duration_hours + if e.billable and e.project.billable: + project_hours[e.project.id]['billable_hours'] += e.duration_hours + top_projects = sorted(project_hours.values(), key=lambda x: x['hours'], reverse=True)[:5] + return render_template('main/dashboard.html', active_timer=active_timer, recent_entries=recent_entries, active_projects=active_projects, today_hours=today_hours, week_hours=week_hours, - month_hours=month_hours) + month_hours=month_hours, + top_projects=top_projects) @main_bp.route('/_health') def health_check(): diff --git a/app/static/base.css b/app/static/base.css deleted file mode 100644 index d6850c5..0000000 --- a/app/static/base.css +++ /dev/null @@ -1,5144 +0,0 @@ -:root { - /* Primary Color Palette - Enhanced Modern Blue */ - --primary-color: #3b82f6; - --primary-dark: #2563eb; - --primary-light: #93c5fd; - --primary-50: #eff6ff; - --primary-100: #dbeafe; - --primary-200: #bfdbfe; - --primary-300: #93c5fd; - --primary-400: #60a5fa; - --primary-500: #3b82f6; - --primary-600: #2563eb; - --primary-700: #1d4ed8; - --primary-800: #1e40af; - --primary-900: #1e3a8a; - - /* Semantic Color System */ - --secondary-color: #64748b; - --success-color: #10b981; - --success-light: #d1fae5; - --danger-color: #ef4444; - --danger-light: #fee2e2; - --warning-color: #f59e0b; - --warning-light: #fef3c7; - --info-color: #06b6d4; - --info-light: #cffafe; - - /* Neutral Color Palette - Enhanced */ - --gray-50: #f9fafb; - --gray-100: #f3f4f6; - --gray-200: #e5e7eb; - --gray-300: #d1d5db; - --gray-400: #9ca3af; - --gray-500: #6b7280; - --gray-600: #4b5563; - --gray-700: #374151; - --gray-800: #1f2937; - --gray-900: #111827; - - /* Background Colors - Modern Hierarchy */ - --dark-color: #1e293b; - --light-color: #f8fafc; - --body-bg: #ffffff; - --surface-color: #ffffff; - --surface-variant: #f8fafc; - --surface-hover: #f1f5f9; - --surface-pressed: #e2e8f0; - - /* Border and Divider Colors - Refined */ - --border-color: #e2e8f0; - --border-light: #f1f5f9; - --border-strong: #cbd5e1; - --divider-color: #e2e8f0; - - /* Text Colors - Improved Hierarchy */ - --text-primary: #1e293b; - --text-secondary: #475569; - --text-tertiary: #64748b; - --text-muted: #9ca3af; - --text-on-primary: #ffffff; - --text-on-dark: #f8fafc; - - /* Component Backgrounds - Enhanced */ - --navbar-bg: rgba(255, 255, 255, 0.95); - --navbar-border: rgba(226, 232, 240, 0.6); - --dropdown-bg: #ffffff; - --card-bg: #ffffff; - --input-bg: #ffffff; - --input-border: #d1d5db; - --input-focus: #3b82f6; - - /* Visual Effects - Modern Shadows and Gradients */ - --bg-gradient: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%); - --bg-gradient-subtle: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%); - --card-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1); - --card-shadow-hover: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1); - --card-shadow-lg: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1); - --card-shadow-xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25); - --focus-ring: 0 0 0 3px rgba(59, 130, 246, 0.12); - --focus-ring-danger: 0 0 0 3px rgba(239, 68, 68, 0.12); - --focus-ring-success: 0 0 0 3px rgba(16, 185, 129, 0.12); - - /* Spacing and Layout - Refined System */ - --border-radius: 8px; - --border-radius-lg: 12px; - --border-radius-sm: 6px; - --border-radius-xs: 4px; - --border-radius-full: 9999px; - --section-spacing: 2.5rem; - --card-spacing: 1.5rem; - --mobile-section-spacing: 1.5rem; - --mobile-card-spacing: 1rem; - --navbar-height: 72px; - --container-padding: 1.5rem; - --grid-gap: 1.5rem; - --grid-gap-sm: 1rem; - - /* Transitions and Animations - Enhanced */ - --transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); - --transition-fast: all 0.15s cubic-bezier(0.4, 0, 0.2, 1); - --transition-slow: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - --transition-bounce: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55); - --animation-duration: 0.3s; - --animation-timing: cubic-bezier(0.4, 0, 0.2, 1); - - /* Typography - Enhanced Scale */ - --font-family-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; - --font-family-mono: 'SF Mono', Monaco, Inconsolata, 'Roboto Mono', 'Source Code Pro', monospace; - --font-weight-light: 300; - --font-weight-normal: 400; - --font-weight-medium: 500; - --font-weight-semibold: 600; - --font-weight-bold: 700; - --font-weight-extrabold: 800; - --line-height-tight: 1.25; - --line-height-normal: 1.5; - --line-height-relaxed: 1.625; - - /* Interactive States */ - --hover-opacity: 0.9; - --active-opacity: 0.95; - --disabled-opacity: 0.5; - --loading-opacity: 0.6; - - /* Z-Index Scale */ - --z-dropdown: 1000; - --z-sticky: 1020; - --z-fixed: 1030; - --z-modal-backdrop: 1040; - --z-modal: 1050; - --z-popover: 1060; - --z-tooltip: 1070; - --z-toast: 1080; - - /* Bootstrap Integration - Enhanced */ - --bs-body-bg: var(--body-bg); - --bs-body-color: var(--text-primary); - --bs-body-font-family: var(--font-family-sans); - --bs-body-font-size: 0.95rem; - --bs-body-line-height: var(--line-height-normal); - --bs-card-bg: var(--card-bg); - --bs-card-border-color: var(--border-color); - --bs-card-border-radius: var(--border-radius); - --bs-dropdown-bg: var(--dropdown-bg); - --bs-dropdown-border-color: var(--border-color); - --bs-dropdown-link-color: var(--text-secondary); - --bs-dropdown-link-hover-bg: var(--surface-hover); - --bs-dropdown-link-hover-color: var(--text-primary); -} - -/* Force containers to full width unless pages explicitly constrain */ -.container, .container-lg, .container-md, .container-sm, .container-xl, .container-xxl { - max-width: 100% !important; -} - -/* Ensure common blocks stretch */ -.card { width: 100%; } -.table-responsive, .table { width: 100%; } - -/* Dark Theme Variables */ -[data-theme="dark"] { - /* Primary Color Palette - Enhanced for dark theme */ - --primary-color: #60a5fa; - --primary-dark: #3b82f6; - --primary-light: #93c5fd; - --primary-50: #1e3a8a; - --primary-100: #1e40af; - --primary-200: #1d4ed8; - --primary-300: #2563eb; - --primary-400: #3b82f6; - --primary-500: #60a5fa; - --primary-600: #93c5fd; - --primary-700: #bfdbfe; - --primary-800: #dbeafe; - --primary-900: #eff6ff; - - /* Semantic Color System - Dark theme */ - --secondary-color: #94a3b8; - --success-color: #34d399; - --success-light: #064e3b; - --danger-color: #f87171; - --danger-light: #7f1d1d; - --warning-color: #fbbf24; - --warning-light: #78350f; - --info-color: #38bdf8; - --info-light: #164e63; - - /* Neutral Color Palette - Dark theme */ - --gray-50: #0f172a; - --gray-100: #1e293b; - --gray-200: #334155; - --gray-300: #475569; - --gray-400: #64748b; - --gray-500: #94a3b8; - --gray-600: #cbd5e1; - --gray-700: #e2e8f0; - --gray-800: #f1f5f9; - --gray-900: #f8fafc; - - /* Background Colors - Dark theme specific */ - --dark-color: #0f172a; - --light-color: #1e293b; - --body-bg: #0b1220; - --surface-color: #0f172a; - --surface-variant: #1e293b; - --surface-hover: #334155; - --surface-pressed: #475569; - - /* Border and Divider Colors - Dark theme */ - --border-color: #334155; - --border-light: #1e293b; - --border-strong: #475569; - --divider-color: #334155; - - /* Text Colors - Dark theme */ - --text-primary: #f1f5f9; - --text-secondary: #cbd5e1; - --text-tertiary: #94a3b8; - --text-muted: #64748b; - --text-on-primary: #ffffff; - --text-on-dark: #0f172a; - - /* Component Backgrounds - Dark theme */ - --navbar-bg: rgba(11, 18, 32, 0.95); - --navbar-border: rgba(51, 65, 85, 0.6); - --dropdown-bg: #0f172a; - --card-bg: #0f172a; - --input-bg: #1e293b; - --input-border: #475569; - --input-focus: #60a5fa; - - /* Visual Effects - Dark theme */ - --bg-gradient: linear-gradient(135deg, #1e3a8a 0%, #1d4ed8 100%); - --bg-gradient-subtle: linear-gradient(135deg, #1e293b 0%, #334155 100%); - --card-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px -1px rgba(0, 0, 0, 0.4); - --card-shadow-hover: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -4px rgba(0, 0, 0, 0.4); - --card-shadow-lg: 0 20px 25px -5px rgba(0, 0, 0, 0.4), 0 8px 10px -6px rgba(0, 0, 0, 0.4); - --card-shadow-xl: 0 25px 50px -12px rgba(0, 0, 0, 0.6); - --focus-ring: 0 0 0 3px rgba(96, 165, 250, 0.2); - --focus-ring-danger: 0 0 0 3px rgba(248, 113, 113, 0.2); - --focus-ring-success: 0 0 0 3px rgba(52, 211, 153, 0.2); - - /* Bootstrap Integration - Dark theme */ - --bs-body-bg: var(--body-bg); - --bs-body-color: var(--text-primary); - --bs-body-font-family: var(--font-family-sans); - --bs-card-bg: var(--card-bg); - --bs-card-border-color: var(--border-color); - --bs-dropdown-bg: var(--dropdown-bg); - --bs-dropdown-border-color: var(--border-color); - --bs-dropdown-link-color: var(--text-secondary); - --bs-dropdown-link-hover-bg: var(--surface-hover); - --bs-dropdown-link-hover-color: var(--text-primary); -} - -* { - box-sizing: border-box; -} - -html, body { - height: 100%; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; -} - -body { - font-family: var(--font-family-sans); - background: var(--body-bg); - color: var(--text-primary); - line-height: var(--line-height-normal); - min-height: 100vh; - display: flex; - flex-direction: column; - font-size: 0.95rem; - font-weight: var(--font-weight-normal); - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - text-rendering: optimizeLegibility; - scroll-behavior: smooth; - transition: background-color var(--transition), color var(--transition); - overflow-x: hidden; -} - -/* Base backgrounds in dark theme */ -[data-theme="dark"] body { - background: var(--body-bg); - color: var(--text-primary); -} - -main { - flex: 1 0 auto; - display: block; - padding-bottom: var(--section-spacing); - animation: fadeIn 0.4s cubic-bezier(0.16, 1, 0.3, 1); -} - -@keyframes fadeIn { - from { - opacity: 0; - transform: translateY(20px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -/* Enhanced Container Layout */ -.container { - max-width: 1400px; - padding-left: var(--container-padding); - padding-right: var(--container-padding); -} - -.container-fluid { - padding-left: var(--container-padding); - padding-right: var(--container-padding); -} - -/* Responsive container padding */ -@media (max-width: 768px) { - .container, - .container-fluid { - padding-left: 1rem; - padding-right: 1rem; - } -} - -/* Improved Section Spacing */ -.section-spacing { - margin-bottom: var(--section-spacing); -} - -.section-spacing:last-child { - margin-bottom: 0; -} - -/* Enhanced Card Layout - Modern Design */ -.card { - border: 1px solid var(--border-color); - box-shadow: var(--card-shadow); - border-radius: var(--border-radius-lg); - transition: var(--transition-slow); - background: var(--card-bg); - overflow: hidden; - margin-bottom: var(--card-spacing); - position: relative; - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); -} - -/* Removed general card hover effect - only interactive cards should have hover effects */ - -/* Simplified card variants */ -.card.card-elevated { - box-shadow: var(--card-shadow-lg); -} - -/* Ensure all card variants have consistent border radius */ -.card { - border-radius: var(--border-radius-lg) !important; -} - -.card-header { - border-top-left-radius: var(--border-radius-lg) !important; - border-top-right-radius: var(--border-radius-lg) !important; - border-bottom-left-radius: 0 !important; - border-bottom-right-radius: 0 !important; -} - -.card-footer { - border-bottom-left-radius: var(--border-radius-lg) !important; - border-bottom-right-radius: var(--border-radius-lg) !important; - border-top-left-radius: 0 !important; - border-top-right-radius: 0 !important; -} - -[data-theme="dark"] .card, -[data-theme="dark"] .modal-content, -[data-theme="dark"] .dropdown-menu, -[data-theme="dark"] .mobile-table-row, -[data-theme="dark"] .table tr { - background: #0f172a !important; - color: var(--text-secondary); - border-color: var(--border-color) !important; -} - -[data-theme="dark"] .card-header, -[data-theme="dark"] .alert, -[data-theme="dark"] .table td, -[data-theme="dark"] .table th { - background: #0f172a; - color: var(--text-secondary); - border-color: var(--border-color); -} - -[data-theme="dark"] .card a:hover .card-body { background-color: #111827; } -[data-theme="dark"] .dropdown-item { background-color: #0f172a !important; color: var(--text-secondary) !important; } -[data-theme="dark"] .dropdown-item:hover { background-color: #111827 !important; } -[data-theme="dark"] .navbar .dropdown-menu { --bs-dropdown-bg: #0f172a; } - -.card:last-child { - margin-bottom: 0; -} - -.card.hover-lift:hover { - box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15), 0 6px 16px rgba(0, 0, 0, 0.1); - transform: translateY(-6px) scale(1.01); - border-color: var(--primary-300); -} - -.card.hover-lift { - transition: all var(--transition-slow) var(--animation-timing); - cursor: pointer; -} - -.card.hover-lift:active { - transform: translateY(-2px) scale(1.01); - transition: all var(--transition-fast); -} - -.card a { - text-decoration: none; - color: inherit; -} - -.card a:hover { - text-decoration: none; -} - -/* Quick action card hover effects */ -.card a:hover .card-body { - background-color: var(--light-color); -} - -.card a:hover .bg-primary.bg-opacity-10 { - background-color: rgba(59, 130, 246, 0.2) !important; -} - -.card a:hover .bg-secondary.bg-opacity-10 { - background-color: rgba(100, 116, 139, 0.2) !important; -} - -.card a:hover .bg-info.bg-opacity-10 { - background-color: rgba(8, 145, 178, 0.2) !important; -} - -.card a:hover .bg-warning.bg-opacity-10 { - background-color: rgba(217, 119, 6, 0.2) !important; -} - -.card-header { - background: var(--card-bg); - border-bottom: 1px solid var(--border-color); - padding: 1.75rem 2rem; - font-weight: var(--font-weight-bold); - color: var(--text-primary); - font-size: 1.125rem; - border-top-left-radius: var(--border-radius-lg); - border-top-right-radius: var(--border-radius-lg); - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - position: relative; - letter-spacing: -0.02em; -} - -.card-header.card-header-lg { - padding: 2rem 2.5rem; - font-size: 1.25rem; -} - -.card-header.card-header-sm { - padding: 1.25rem 1.5rem; - font-size: 1rem; -} - -.card-body { - padding: 2rem; - color: var(--text-primary); -} - -.card-body.card-body-lg { - padding: 2.5rem; -} - -.card-body.card-body-sm { - padding: 1.5rem; -} - -.card-footer { - background: var(--surface-variant); - border-top: 1px solid var(--border-color); - padding: 1.5rem 2rem; - border-bottom-left-radius: var(--border-radius-lg); - border-bottom-right-radius: var(--border-radius-lg); - color: var(--text-secondary); -} - -/* Enhanced Button System - Modern Styling with Rounded Corners */ -.btn { - border-radius: var(--border-radius-lg) !important; - font-weight: var(--font-weight-semibold) !important; - padding: 0.875rem 1.5rem !important; - transition: var(--transition-slow) !important; - position: relative !important; - font-size: 0.95rem !important; - min-height: 48px !important; - display: inline-flex !important; - align-items: center !important; - justify-content: center !important; - text-decoration: none !important; - cursor: pointer !important; - gap: 0.5rem !important; - line-height: var(--line-height-tight) !important; - -webkit-tap-highlight-color: transparent !important; - user-select: none !important; - white-space: nowrap !important; - overflow: hidden !important; - font-family: var(--font-family-sans) !important; - letter-spacing: 0.01em !important; - - /* Default neutral styling with enhanced visual hierarchy */ - border: 2px solid var(--input-border) !important; - background: var(--surface-color) !important; - color: var(--text-primary) !important; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.06) !important; -} - -.btn::after { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), transparent); - opacity: 0; - transition: opacity var(--transition); - pointer-events: none; -} - -.btn:hover::after { - opacity: 0.35; -} - -/* Button focus states */ -.btn:focus { - outline: none; - box-shadow: var(--focus-ring); -} - -.btn:focus:not(:focus-visible) { - box-shadow: none; -} - -.btn:focus-visible { - box-shadow: var(--focus-ring); -} - -.btn:hover { - background: var(--surface-hover) !important; - border-color: var(--primary-color) !important; - color: var(--text-primary) !important; - transform: translateY(-2px) !important; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12) !important; -} - -.btn:active { - transform: translateY(0) scale(0.98) !important; - transition: var(--transition-fast) !important; - box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05) !important; -} - -.btn i { - color: #6b7280; - margin-right: 0.375rem; -} - -.btn:hover i { - color: #4b5563; -} - -/* Primary button styling - Enhanced */ -.btn-primary { - background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-600) 100%) !important; - border-color: var(--primary-color) !important; - color: var(--text-on-primary) !important; - box-shadow: 0 2px 4px rgba(59, 130, 246, 0.2), 0 1px 2px rgba(59, 130, 246, 0.1) !important; - position: relative !important; - overflow: hidden !important; -} - -.btn-primary::before { - content: ''; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); - transition: left 0.5s; -} - -.btn-primary:hover::before { - left: 100%; -} - -.btn-primary:hover { - background: linear-gradient(135deg, var(--primary-600) 0%, var(--primary-700) 100%) !important; - border-color: var(--primary-600) !important; - color: var(--text-on-primary) !important; - transform: translateY(-2px) !important; - box-shadow: 0 8px 20px rgba(59, 130, 246, 0.4), 0 4px 12px rgba(59, 130, 246, 0.3) !important; -} - -.btn-primary:focus { - box-shadow: var(--focus-ring), 0 2px 4px rgba(59, 130, 246, 0.2); -} - -.btn-primary:active { - background: linear-gradient(135deg, var(--primary-700) 0%, var(--primary-800) 100%); - transform: translateY(0) scale(0.98); -} - -/* Success button styling - Enhanced */ -.btn-success { - background: linear-gradient(135deg, var(--success-color) 0%, #059669 100%) !important; - border-color: var(--success-color) !important; - color: var(--text-on-primary) !important; - box-shadow: 0 2px 4px rgba(16, 185, 129, 0.2), 0 1px 2px rgba(16, 185, 129, 0.1) !important; - position: relative !important; - overflow: hidden !important; -} - -.btn-success::before { - content: ''; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); - transition: left 0.5s; -} - -.btn-success:hover::before { - left: 100%; -} - -.btn-success:hover { - background: linear-gradient(135deg, #059669 0%, #047857 100%) !important; - border-color: #059669 !important; - color: var(--text-on-primary) !important; - transform: translateY(-1px) !important; - box-shadow: 0 3px 10px rgba(16, 185, 129, 0.18), 0 1px 3px rgba(16, 185, 129, 0.12) !important; -} - -/* Danger button styling */ -.btn-danger { - background: var(--danger-color); - border-color: var(--danger-color); - color: var(--text-on-primary); - box-shadow: 0 1px 3px rgba(220, 38, 38, 0.3); -} - -.btn-danger:hover { - background: #b91c1c; - border-color: #b91c1c; - color: var(--text-on-primary); - box-shadow: 0 3px 10px rgba(220, 38, 38, 0.25); -} - -/* Outline button styling - Enhanced */ -.btn-outline-primary { - background: transparent !important; - border: 2px solid var(--primary-color) !important; - color: var(--primary-color) !important; - position: relative !important; - overflow: hidden !important; - backdrop-filter: blur(8px) !important; - -webkit-backdrop-filter: blur(8px) !important; -} - -.btn-outline-primary::before { - content: ''; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(59, 130, 246, 0.1), transparent); - transition: left 0.5s; -} - -.btn-outline-primary:hover::before { - left: 100%; -} - -.btn-outline-primary:hover { - background: var(--primary-color) !important; - border-color: var(--primary-color) !important; - color: var(--text-on-primary) !important; - transform: translateY(-2px) !important; - box-shadow: 0 8px 25px rgba(59, 130, 246, 0.3) !important; -} - -/* Dark Mode Button Overrides - Comprehensive Fix */ - -/* Primary buttons in dark mode */ -[data-theme="dark"] .btn-primary { - background: var(--primary-color); - border-color: var(--primary-color); - color: var(--text-on-primary); - box-shadow: 0 2px 4px rgba(96, 165, 250, 0.3); -} - -[data-theme="dark"] .btn-primary:hover { - background: var(--primary-dark); - border-color: var(--primary-dark); - color: var(--text-on-primary); - box-shadow: 0 4px 12px rgba(96, 165, 250, 0.4); - transform: translateY(-1px); -} - -[data-theme="dark"] .btn-primary:focus { - box-shadow: var(--focus-ring), 0 2px 4px rgba(96, 165, 250, 0.3); -} - -/* Success buttons in dark mode */ -[data-theme="dark"] .btn-success { - background: var(--success-color); - border-color: var(--success-color); - color: var(--text-on-primary); - box-shadow: 0 2px 4px rgba(16, 185, 129, 0.3); -} - -[data-theme="dark"] .btn-success:hover { - background: #059669; - border-color: #059669; - color: var(--text-on-primary); - box-shadow: 0 4px 12px rgba(16, 185, 129, 0.4); - transform: translateY(-1px); -} - -/* Danger buttons in dark mode */ -[data-theme="dark"] .btn-danger { - background: var(--danger-color); - border-color: var(--danger-color); - color: var(--text-on-primary); - box-shadow: 0 2px 4px rgba(239, 68, 68, 0.3); -} - -[data-theme="dark"] .btn-danger:hover { - background: #dc2626; - border-color: #dc2626; - color: var(--text-on-primary); - box-shadow: 0 4px 12px rgba(239, 68, 68, 0.4); - transform: translateY(-1px); -} - -/* Warning buttons in dark mode */ -[data-theme="dark"] .btn-warning { - background: var(--warning-color); - border-color: var(--warning-color); - color: var(--text-on-primary); - box-shadow: 0 2px 4px rgba(245, 158, 11, 0.3); -} - -[data-theme="dark"] .btn-warning:hover { - background: #d97706; - border-color: #d97706; - color: var(--text-on-primary); - box-shadow: 0 4px 12px rgba(245, 158, 11, 0.4); - transform: translateY(-1px); -} - -/* Info buttons in dark mode */ -[data-theme="dark"] .btn-info { - background: var(--info-color); - border-color: var(--info-color); - color: var(--text-on-primary); - box-shadow: 0 2px 4px rgba(56, 189, 248, 0.3); -} - -[data-theme="dark"] .btn-info:hover { - background: #0284c7; - border-color: #0284c7; - color: var(--text-on-primary); - box-shadow: 0 4px 12px rgba(56, 189, 248, 0.4); - transform: translateY(-1px); -} - -/* Secondary buttons in dark mode */ -[data-theme="dark"] .btn-secondary { - background: var(--text-muted); - border-color: var(--text-muted); - color: var(--surface-color); - box-shadow: 0 2px 4px rgba(148, 163, 184, 0.3); -} - -[data-theme="dark"] .btn-secondary:hover { - background: var(--text-secondary); - border-color: var(--text-secondary); - color: var(--surface-color); - box-shadow: 0 4px 12px rgba(148, 163, 184, 0.4); - transform: translateY(-1px); -} - -/* Outline buttons in dark mode */ -[data-theme="dark"] .btn-outline-primary { - background: transparent; - border: 2px solid var(--primary-color); - color: var(--primary-color); -} - -[data-theme="dark"] .btn-outline-primary:hover { - background: var(--primary-color); - border-color: var(--primary-color); - color: var(--text-on-primary); - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(96, 165, 250, 0.3); -} - -[data-theme="dark"] .btn-outline-secondary { - background: transparent; - border: 2px solid var(--text-muted); - color: var(--text-muted); -} - -[data-theme="dark"] .btn-outline-secondary:hover { - background: var(--text-muted); - border-color: var(--text-muted); - color: var(--surface-color); - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(148, 163, 184, 0.3); -} - -[data-theme="dark"] .btn-outline-success { - background: transparent; - border: 2px solid var(--success-color); - color: var(--success-color); -} - -[data-theme="dark"] .btn-outline-success:hover { - background: var(--success-color); - border-color: var(--success-color); - color: var(--text-on-primary); - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3); -} - -[data-theme="dark"] .btn-outline-danger { - background: transparent; - border: 2px solid var(--danger-color); - color: var(--danger-color); -} - -[data-theme="dark"] .btn-outline-danger:hover { - background: var(--danger-color); - border-color: var(--danger-color); - color: var(--text-on-primary); - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3); -} - -[data-theme="dark"] .btn-outline-warning { - background: transparent; - border: 2px solid var(--warning-color); - color: var(--warning-color); -} - -[data-theme="dark"] .btn-outline-warning:hover { - background: var(--warning-color); - border-color: var(--warning-color); - color: var(--text-on-primary); - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(245, 158, 11, 0.3); -} - -[data-theme="dark"] .btn-outline-info { - background: transparent; - border: 2px solid var(--info-color); - color: var(--info-color); -} - -[data-theme="dark"] .btn-outline-info:hover { - background: var(--info-color); - border-color: var(--info-color); - color: var(--text-on-primary); - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(56, 189, 248, 0.3); -} - -/* Modern header button style */ -.btn-header { - padding: 0.5rem 1rem; - font-size: 0.875rem; - font-weight: 500; - border-radius: 8px; - border: 1px solid transparent; - transition: all 0.2s ease; - text-decoration: none; - display: inline-flex; - align-items: center; - gap: 0.375rem; - min-height: 36px; -} - -.btn-header.btn-primary { - background: #f9fafb; - color: #6b7280; - border-color: #6b7280; -} - -.btn-header.btn-primary:hover { - background: #f3f4f6; - border-color: #4b5563; - color: #4b5563; - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(107, 114, 128, 0.15); -} - -.btn-header.btn-outline-primary { - background: transparent; - color: #6b7280; - border-color: #6b7280; -} - -.btn-header.btn-outline-primary:hover { - background: #f9fafb; - color: #4b5563; - border-color: #4b5563; - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(107, 114, 128, 0.15); - -webkit-tap-highlight-color: transparent; - gap: 0.5rem; -} - -.btn:active { - transform: scale(0.98); -} - -/* Primary button styling is handled above - removed duplicate */ - -/* Soft button variants - Uniform Grey */ -.btn-soft-primary { - color: #6b7280; - background: rgba(107, 114, 128, 0.1); - border: 1px solid rgba(107, 114, 128, 0.2); -} -.btn-soft-primary:hover { background: rgba(107, 114, 128, 0.15); color: #4b5563; } - -.btn-soft-secondary { - color: #6b7280; - background: rgba(107, 114, 128, 0.1); - border: 1px solid rgba(107, 114, 128, 0.2); -} -.btn-soft-secondary:hover { background: rgba(107, 114, 128, 0.15); color: #4b5563; } - -.btn-soft-success { - color: #6b7280; - background: rgba(107, 114, 128, 0.1); - border: 1px solid rgba(107, 114, 128, 0.2); -} -.btn-soft-success:hover { background: rgba(107, 114, 128, 0.15); color: #4b5563; } - -.btn-soft-danger { - color: #6b7280; - background: rgba(107, 114, 128, 0.1); - border: 1px solid rgba(107, 114, 128, 0.2); -} -.btn-soft-danger:hover { background: rgba(107, 114, 128, 0.15); color: #4b5563; } - -/* Icon-only buttons */ -.btn-icon { - padding: 0.5rem; - width: 36px; - height: 36px; - min-height: 36px; - display: inline-flex; - align-items: center; - justify-content: center; -} -.btn-icon.btn-sm { width: 32px; height: 32px; min-height: 32px; } -.btn-icon i { font-size: 0.95rem; } - -/* Global theme toggle button - uniform grey */ -/* Theme toggle styles removed - button no longer in header */ - -/* Success and danger button styling is handled above - removed duplicate */ - -/* Light theme outline button styles */ -.btn-outline-primary { - background: transparent; - border: 2px solid var(--primary-color); - color: var(--primary-color); -} - -.btn-outline-primary:hover { - background: var(--primary-color); - border-color: var(--primary-color); - color: var(--text-on-primary); - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3); -} - -.btn-outline-secondary { - background: transparent; - border: 2px solid var(--text-muted); - color: var(--text-muted); -} - -.btn-outline-secondary:hover { - background: var(--text-muted); - border-color: var(--text-muted); - color: var(--surface-color); - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(148, 163, 184, 0.3); -} - -/* Outline light buttons in dark mode */ -[data-theme="dark"] .btn-outline-light { - background: transparent; - border: 2px solid var(--text-secondary); - color: var(--text-secondary); -} - -[data-theme="dark"] .btn-outline-light:hover { - background: var(--text-secondary); - border-color: var(--text-secondary); - color: var(--surface-color); - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(203, 213, 225, 0.3); -} - -/* Keep outline secondary buttons light when opened/active */ -.btn-outline-secondary:focus, -.btn-outline-secondary:active, -.btn-outline-secondary.dropdown-toggle.show, -.show > .btn-outline-secondary.dropdown-toggle { - background: #f9fafb; - border-color: #4b5563; - color: #4b5563; -} - -/* Unify small/large sizes */ -.btn-sm { - padding: 0.4rem 0.65rem; - font-size: 0.85rem; - min-height: 36px; -} -.btn-lg { - padding: 0.9rem 1.25rem; - font-size: 1.05rem; - min-height: 56px; -} - -/* Enhanced Form Layout */ -.form-control, .form-select { - border: 2px solid var(--border-color); - border-radius: var(--border-radius); - padding: 0.875rem 1rem; - font-size: 0.95rem; - transition: var(--transition); - background: var(--gray-50); - min-height: 48px; /* baseline */ - font-family: var(--font-family-sans); -} - -[data-theme="dark"] .form-control, -[data-theme="dark"] .form-select { - background: var(--input-bg); - color: var(--text-primary); - border-color: var(--border-color); -} - -[data-theme="dark"] .form-control:focus, -[data-theme="dark"] .form-select:focus { - background: var(--input-bg); - color: var(--text-primary); - border-color: var(--primary-color); - box-shadow: var(--focus-ring); -} - -[data-theme="dark"] textarea.form-control { - background: var(--input-bg); - color: var(--text-primary); - border-color: var(--border-color); -} - -[data-theme="dark"] .form-control::placeholder { - color: var(--text-muted); - opacity: 0.8; -} - -[data-theme="dark"] .form-select option { - background: var(--input-bg); - color: var(--text-primary); -} - -/* EasyMDE (Markdown editor) enhanced theming */ -.EasyMDEContainer { - border: 1px solid var(--border-color); - border-radius: var(--border-radius-sm); - overflow: hidden; - background: transparent; -} - -/* Toolbar */ -.EasyMDEContainer .editor-toolbar { - background: var(--bs-body-bg, #ffffff) !important; - border-bottom: 1px solid var(--border-color); - padding: 0.375rem 0.5rem; - box-shadow: inset 0 -1px 0 rgba(0,0,0,0.05); -} -.EasyMDEContainer .editor-toolbar a { - color: var(--text-secondary) !important; - border-radius: 6px; - height: 32px; - width: 32px; - display: inline-flex; - align-items: center; - justify-content: center; - transition: var(--transition); - opacity: 0.9; -} -.EasyMDEContainer .editor-toolbar a:hover, -.EasyMDEContainer .editor-toolbar a.active { - background: var(--light-color) !important; - color: var(--text-primary) !important; - box-shadow: inset 0 0 0 2px var(--primary-color); - opacity: 1; -} -.EasyMDEContainer .editor-toolbar .separator { - border-left: 1px solid var(--border-color); - margin: 0 0.35rem; -} - -/* Editor surface */ -.EasyMDEContainer .CodeMirror, -.EasyMDEContainer .CodeMirror-scroll, -.EasyMDEContainer .cm-s-easymde.CodeMirror, -.EasyMDEContainer .cm-s-easymde .CodeMirror-scroll { - background: var(--bs-body-bg, #ffffff) !important; - color: var(--text-primary) !important; -} -.EasyMDEContainer .cm-s-easymde.CodeMirror { - border-top: none !important; /* aligns with toolbar */ -} -.EasyMDEContainer .cm-s-easymde .CodeMirror-gutters { - background: var(--bs-body-bg, #ffffff) !important; - border-right: 1px solid var(--border-color) !important; -} -.EasyMDEContainer .CodeMirror { - min-height: 280px; - font-size: 0.95rem; - line-height: 1.55; -} -.EasyMDEContainer .CodeMirror-scroll { padding: 0.75rem 1rem; } -.EasyMDEContainer .CodeMirror pre { color: var(--text-primary) !important; } -.EasyMDEContainer .CodeMirror-cursor { border-left-color: #1e293b !important; } -.EasyMDEContainer .CodeMirror .CodeMirror-placeholder { color: #64748b !important; } -.EasyMDEContainer .CodeMirror-selected { background: rgba(59,130,246,0.15) !important; } -.EasyMDEContainer .CodeMirror-focused { box-shadow: 0 0 0 3px rgba(59,130,246,0.12); } - -/* Status bar and preview */ -.EasyMDEContainer .editor-statusbar { - background: var(--bs-body-bg, #ffffff) !important; - color: var(--text-secondary) !important; - border-top: 1px solid var(--border-color); - padding: 0.375rem 0.75rem; -} -.EasyMDEContainer .editor-preview, -.EasyMDEContainer .editor-preview-side { - background: var(--bs-body-bg, #ffffff) !important; - color: var(--text-primary) !important; -} - -/* Light token colors for readability */ -.EasyMDEContainer .cm-header { color: #1e40af !important; } -.EasyMDEContainer .cm-strong { color: #1e293b !important; } -.EasyMDEContainer .cm-em { color: #dc2626 !important; } -.EasyMDEContainer .cm-quote { color: #059669 !important; } -.EasyMDEContainer .cm-link { color: #2563eb !important; text-decoration: underline; } -.EasyMDEContainer .cm-formatting-header { color: #2563eb !important; } -.EasyMDEContainer .cm-url { color: #2563eb !important; } -.EasyMDEContainer .cm-code { color: #dc2626 !important; } -.EasyMDEContainer .cm-hr { color: #64748b !important; } - -/* Dark theme */ -[data-theme="dark"] .EasyMDEContainer .editor-toolbar { - background: #0b1220 !important; - border-color: var(--border-color) !important; - box-shadow: inset 0 -1px 0 rgba(255,255,255,0.03); -} -[data-theme="dark"] .EasyMDEContainer .editor-toolbar a { - color: var(--text-secondary) !important; - opacity: 0.95; -} -[data-theme="dark"] .EasyMDEContainer .editor-toolbar a:hover, -[data-theme="dark"] .EasyMDEContainer .editor-toolbar a.active { - background: #111827 !important; - color: var(--text-primary) !important; -} - -[data-theme="dark"] .EasyMDEContainer .CodeMirror, -[data-theme="dark"] .EasyMDEContainer .CodeMirror-scroll, -[data-theme="dark"] .EasyMDEContainer .cm-s-easymde.CodeMirror, -[data-theme="dark"] .EasyMDEContainer .cm-s-easymde .CodeMirror-scroll { - background: #0f172a !important; - color: var(--text-primary) !important; -} -[data-theme="dark"] .EasyMDEContainer .cm-s-easymde.CodeMirror { - border-top: none !important; -} -[data-theme="dark"] .EasyMDEContainer .cm-s-easymde .CodeMirror-gutters { - background: #0f172a !important; - border-right: 1px solid var(--border-color) !important; -} -[data-theme="dark"] .EasyMDEContainer .CodeMirror-selected { background: rgba(59,130,246,0.25) !important; } -[data-theme="dark"] .EasyMDEContainer .CodeMirror pre { color: var(--text-primary) !important; } -[data-theme="dark"] .EasyMDEContainer .CodeMirror-cursor { border-left-color: #e5e7eb !important; } -[data-theme="dark"] .EasyMDEContainer .CodeMirror .CodeMirror-placeholder { color: #64748b !important; } - -/* Dark token colors */ -[data-theme="dark"] .EasyMDEContainer .cm-header { color: #93c5fd !important; } -[data-theme="dark"] .EasyMDEContainer .cm-strong { color: #e5e7eb !important; } -[data-theme="dark"] .EasyMDEContainer .cm-em { color: #fca5a5 !important; } -[data-theme="dark"] .EasyMDEContainer .cm-quote { color: #a7f3d0 !important; } -[data-theme="dark"] .EasyMDEContainer .cm-link { color: #60a5fa !important; text-decoration: underline; } -[data-theme="dark"] .EasyMDEContainer .cm-formatting-header { color: #60a5fa !important; } - -/* ========================================== - Markdown Editor Wrapper (Task forms) - ========================================== */ - -.markdown-editor-wrapper { - position: relative; - border-radius: var(--border-radius); - overflow: hidden; -} - -.markdown-editor-wrapper .EasyMDEContainer { - border: none !important; /* outer border handled by inner parts */ - border-radius: 12px !important; - overflow: hidden; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); -} - -.markdown-editor-wrapper .editor-toolbar { - background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%) !important; - border: 2px solid #e2e8f0 !important; - border-top: none !important; - border-radius: 0 0 12px 12px !important; - position: relative; -} - -.markdown-editor-wrapper .editor-toolbar a { - height: 34px !important; - width: 34px !important; - display: inline-flex !important; - align-items: center !important; - justify-content: center !important; - border-radius: 6px !important; - transition: var(--transition) !important; - color: #64748b !important; - position: relative !important; - overflow: hidden !important; -} - -.markdown-editor-wrapper .editor-toolbar a:hover, -.markdown-editor-wrapper .editor-toolbar a.active { - background: linear-gradient(135deg, #e2e8f0 0%, #cbd5e1 100%) !important; - box-shadow: 0 4px 12px rgba(0,0,0,0.15) !important; - color: var(--primary-color) !important; - transform: translateY(-1px) scale(1.05); -} - -.markdown-editor-wrapper .CodeMirror, -.markdown-editor-wrapper .editor-preview-side { - background: #ffffff !important; - padding: 1rem 1.25rem !important; - font-size: 0.95rem !important; - line-height: 1.6 !important; -} - -[data-theme="dark"] .markdown-editor-wrapper .editor-toolbar { - background: linear-gradient(135deg, #0b1220 0%, #1f2a44 100%) !important; - border-color: #1f2a44 !important; -} - -[data-theme="dark"] .markdown-editor-wrapper .CodeMirror, -[data-theme="dark"] .markdown-editor-wrapper .editor-preview-side { - background: #0f172a !important; - color: var(--text-primary) !important; -} - -/* Toast UI Editor polish within wrapper */ -.markdown-editor-wrapper .toastui-editor-defaultUI { - border: 1px solid var(--border-color); - border-radius: 12px; - overflow: hidden; - background: var(--bs-body-bg, #ffffff); -} -.markdown-editor-wrapper .toastui-editor-defaultUI-toolbar { - background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%); - border-bottom: 1px solid var(--border-color); - padding: 8px 10px; - position: sticky; - top: 0; - z-index: 5; -} -.markdown-editor-wrapper .toastui-editor-defaultUI-toolbar .toastui-editor-toolbar-icons { - border-radius: 6px; - border: 1px solid transparent; - background-color: transparent; - box-shadow: none; -} -.markdown-editor-wrapper .toastui-editor-defaultUI-toolbar .toastui-editor-toolbar-icons:hover { - background: linear-gradient(135deg, #e2e8f0 0%, #cbd5e1 100%); -} -.markdown-editor-wrapper .toastui-editor-contents, -.markdown-editor-wrapper .ProseMirror { - font-size: 0.95rem; - line-height: 1.65; -} -.markdown-editor-wrapper .toastui-editor-contents { - color: var(--text-primary); -} -.markdown-editor-wrapper .toastui-editor-main .toastui-editor-md-container { - border-right: 1px solid var(--border-color); -} -.markdown-editor-wrapper:focus-within .toastui-editor-defaultUI { - box-shadow: 0 0 0 3px rgba(59,130,246,0.15); -} -.markdown-editor-wrapper .toastui-editor-contents pre, -.markdown-editor-wrapper .toastui-editor-contents code { - background: #f8fafc; -} -.markdown-editor-wrapper .toastui-editor-contents pre { - border: 1px solid var(--border-color); - border-radius: 8px; - padding: 14px 16px; - overflow-x: auto; -} -.markdown-editor-wrapper .toastui-editor-contents pre code { - background: transparent; - font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', 'Source Code Pro', monospace; - font-size: 0.92em; -} -.markdown-editor-wrapper .toastui-editor-contents code:not(pre code) { - background: #f1f5f9; - border: 1px solid rgba(0,0,0,0.05); - border-radius: var(--border-radius); - padding: 2px 6px; - font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', 'Source Code Pro', monospace; -} -.markdown-editor-wrapper .toastui-editor-contents blockquote { - border-left: 4px solid var(--primary-color); - background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%); - padding: 12px 16px; - border-radius: 0 8px 8px 0; -} -.markdown-editor-wrapper .toastui-editor-contents hr { - border: none; - height: 2px; - background: linear-gradient(90deg, transparent, var(--border-color), transparent); - margin: 1.25rem 0; -} -.markdown-editor-wrapper .toastui-editor-contents a { - color: var(--primary-color); - text-decoration: underline; -} -.markdown-editor-wrapper .toastui-editor-contents ul, -.markdown-editor-wrapper .toastui-editor-contents ol { - padding-left: 1.25rem; -} -.markdown-editor-wrapper .toastui-editor-contents li + li { - margin-top: 0.25rem; -} -.markdown-editor-wrapper .toastui-editor-contents input[type="checkbox"] { - width: 1rem; - height: 1rem; - margin-right: 0.5rem; -} -.markdown-editor-wrapper .toastui-editor-contents table { - width: 100%; - border-collapse: collapse; - border: 1px solid var(--border-color); - border-radius: 8px; - overflow: hidden; -} -.markdown-editor-wrapper .toastui-editor-contents th, -.markdown-editor-wrapper .toastui-editor-contents td { - border: 1px solid var(--border-color); - padding: 10px 12px; - text-align: left; -} -.markdown-editor-wrapper .toastui-editor-contents th { - background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%); - color: var(--text-primary); -} -.markdown-editor-wrapper .toastui-editor-contents tr:nth-child(even) td { - background: rgba(59,130,246,0.03); -} -.markdown-editor-wrapper .toastui-editor-contents img { - max-width: 100%; - height: auto; - border-radius: 8px; - border: 1px solid var(--border-color); -} -.markdown-editor-wrapper .toastui-editor-toolbar-icons { - transition: transform 0.15s ease; -} -.markdown-editor-wrapper .toastui-editor-toolbar-icons:active { - transform: translateY(1px) scale(0.98); -} - -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-defaultUI { - border-color: var(--border-color); -} -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-defaultUI-toolbar { - background: linear-gradient(135deg, #0b1220 0%, #1f2a44 100%); - border-bottom-color: var(--border-color); -} -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-main .toastui-editor-md-container { - border-right-color: var(--border-color); -} -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents, -[data-theme="dark"] .markdown-editor-wrapper .ProseMirror { - color: var(--text-primary); -} -[data-theme="dark"] .markdown-editor-wrapper .ProseMirror { - caret-color: #e5e7eb; -} -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents h1, -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents h2, -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents h3, -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents h4, -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents h5, -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents h6 { - color: var(--text-primary); -} -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents a { - color: #93c5fd; -} -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents pre, -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents code { - background: #0f172a; -} -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents pre code { - color: #e5e7eb; -} -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents pre { - border-color: var(--border-color); -} -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents blockquote { - background: linear-gradient(135deg, #1f2a44 0%, #374151 100%); -} -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents code:not(pre code) { - background: #111827; - border-color: var(--border-color); - color: #f472b6; -} -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents th, -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents td { - color: var(--text-primary); -} -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-defaultUI-toolbar .toastui-editor-toolbar-icons { - color: var(--text-secondary); - opacity: 0.95; -} -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents th { - background: linear-gradient(135deg, #1f2a44 0%, #374151 100%); -} -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents tr:nth-child(even) td { - background: rgba(96,165,250,0.06); -} -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-contents hr { - background: linear-gradient(90deg, transparent, #1f2a44, transparent); -} -[data-theme="dark"] .markdown-editor-wrapper .toastui-editor-mode-switch { - color: var(--text-secondary); -} - -/* Enhanced editor surface inside wrapper */ -.markdown-editor-wrapper .EasyMDEContainer .CodeMirror { - border-radius: 12px 12px 0 0 !important; - border: 2px solid #e2e8f0 !important; - border-bottom: none !important; - font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', 'Source Code Pro', monospace !important; - font-size: 14px !important; - line-height: 1.6 !important; - padding: 16px !important; - color: #1e293b !important; - min-height: 300px !important; -} -.markdown-editor-wrapper .EasyMDEContainer .CodeMirror-focused { - border-color: var(--primary-color) !important; - box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1) !important; -} - -/* Toolbar polish */ -.markdown-editor-wrapper .editor-toolbar::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 1px; - background: linear-gradient(90deg, transparent, var(--primary-color), transparent); -} -.markdown-editor-wrapper .editor-toolbar i.separator { - border-left: 1px solid #cbd5e1 !important; - margin: 0 8px !important; - opacity: 0.6; -} - -/* Dark variants */ -[data-theme="dark"] .markdown-editor-wrapper .EasyMDEContainer .CodeMirror { - background: #0f172a !important; - color: #e5e7eb !important; - border-color: #1f2a44 !important; -} -[data-theme="dark"] .markdown-editor-wrapper .EasyMDEContainer .CodeMirror-focused { - border-color: var(--primary-color) !important; - box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.2) !important; -} -[data-theme="dark"] .markdown-editor-wrapper .editor-toolbar::before { - background: linear-gradient(90deg, transparent, #60a5fa, transparent); -} -[data-theme="dark"] .markdown-editor-wrapper .editor-toolbar a { - color: #94a3b8 !important; -} -[data-theme="dark"] .markdown-editor-wrapper .editor-toolbar a:hover, -[data-theme="dark"] .markdown-editor-wrapper .editor-toolbar a.active { - background: linear-gradient(135deg, #1f2a44 0%, #374151 100%) !important; - color: var(--primary-color) !important; -} -[data-theme="dark"] .markdown-editor-wrapper .editor-toolbar i.separator { - border-left-color: #374151 !important; -} - -/* Preview polish */ -.markdown-editor-wrapper .EasyMDEContainer .editor-preview { - background: #ffffff !important; - color: #1e293b !important; - padding: 20px !important; - border-radius: 12px !important; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif !important; - line-height: 1.7 !important; -} -[data-theme="dark"] .markdown-editor-wrapper .EasyMDEContainer .editor-preview { - background: #0f172a !important; - color: #e5e7eb !important; -} -.markdown-editor-wrapper .EasyMDEContainer .editor-preview h1, -.markdown-editor-wrapper .EasyMDEContainer .editor-preview h2, -.markdown-editor-wrapper .EasyMDEContainer .editor-preview h3, -.markdown-editor-wrapper .EasyMDEContainer .editor-preview h4, -.markdown-editor-wrapper .EasyMDEContainer .editor-preview h5, -.markdown-editor-wrapper .EasyMDEContainer .editor-preview h6 { - color: var(--primary-color) !important; - margin-top: 1.5em !important; - margin-bottom: 0.5em !important; - position: relative; -} -.markdown-editor-wrapper .EasyMDEContainer .editor-preview h1::after, -.markdown-editor-wrapper .EasyMDEContainer .editor-preview h2::after, -.markdown-editor-wrapper .EasyMDEContainer .editor-preview h3::after { - content: ''; - position: absolute; - bottom: -4px; - left: 0; - width: 30px; - height: 2px; - background: linear-gradient(90deg, var(--primary-color), transparent); -} -.markdown-editor-wrapper .EasyMDEContainer .editor-preview blockquote { - border-left: 4px solid var(--primary-color) !important; - background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%) !important; - padding: 12px 16px !important; - margin: 16px 0 !important; - border-radius: 0 8px 8px 0 !important; -} -[data-theme="dark"] .markdown-editor-wrapper .EasyMDEContainer .editor-preview blockquote { - background: linear-gradient(135deg, #1f2a44 0%, #374151 100%) !important; -} -.markdown-editor-wrapper .EasyMDEContainer .editor-preview code { - background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%) !important; - color: #e11d48 !important; - padding: 2px 6px !important; - border-radius: var(--border-radius-sm) !important; - font-size: 0.9em !important; - font-weight: 600; - border: 1px solid rgba(225, 29, 72, 0.1); -} -[data-theme="dark"] .markdown-editor-wrapper .EasyMDEContainer .editor-preview code { - background: linear-gradient(135deg, #1f2a44 0%, #374151 100%) !important; - color: #f472b6 !important; - border-color: rgba(244, 114, 182, 0.2); -} -.markdown-editor-wrapper .EasyMDEContainer .editor-preview pre { - background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%) !important; - border: 1px solid #e2e8f0 !important; - border-radius: 8px !important; - padding: 16px !important; - overflow-x: auto !important; - position: relative; -} -.markdown-editor-wrapper .EasyMDEContainer .editor-preview pre::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 1px; - background: linear-gradient(90deg, transparent, var(--primary-color), transparent); -} -[data-theme="dark"] .markdown-editor-wrapper .EasyMDEContainer .editor-preview pre { - background: linear-gradient(135deg, #0b1220 0%, #1f2a44 100%) !important; - border-color: #1f2a44 !important; -} -.markdown-editor-wrapper .EasyMDEContainer .editor-preview table { - border-collapse: collapse !important; - width: 100% !important; - margin: 16px 0 !important; - border-radius: 8px !important; - overflow: hidden !important; - box-shadow: 0 1px 3px rgba(0,0,0,0.1) !important; -} -.markdown-editor-wrapper .EasyMDEContainer .editor-preview th, -.markdown-editor-wrapper .EasyMDEContainer .editor-preview td { - border: 1px solid #e2e8f0 !important; - padding: 8px 12px !important; - text-align: left !important; -} -.markdown-editor-wrapper .EasyMDEContainer .editor-preview th { - background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%) !important; - font-weight: 600 !important; - color: var(--primary-color) !important; -} -[data-theme="dark"] .markdown-editor-wrapper .EasyMDEContainer .editor-preview th, -[data-theme="dark"] .markdown-editor-wrapper .EasyMDEContainer .editor-preview td { - border-color: #1f2a44 !important; -} -[data-theme="dark"] .markdown-editor-wrapper .EasyMDEContainer .editor-preview th { - background: linear-gradient(135deg, #1f2a44 0%, #374151 100%) !important; - color: #60a5fa !important; -} -[data-theme="dark"] .input-group-text { - background: #111827; - color: var(--text-secondary); - border-color: var(--border-color); -} -[data-theme="dark"] .form-text { color: var(--text-muted); } -[data-theme="dark"] .form-control::placeholder { color: #64748b; } -[data-theme="dark"] .form-select option { background: #0f172a; color: var(--text-primary); } -[data-theme="dark"] .form-check-input { - background-color: #0f172a; - border-color: var(--border-color); -} - -.form-control:focus, .form-select:focus { - border-color: var(--primary-color); - box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1); - outline: none; - background: white; -} - -.form-label { - font-weight: 600; - color: var(--text-primary); - margin-bottom: 0.75rem; - font-size: 0.95rem; -} - -/* Enhanced Table Layout */ -.table { - border-radius: var(--border-radius-sm); - overflow: visible; /* Allow dropdowns to overflow */ - margin-bottom: 0; -} - -/* Allow table containers to overflow for dropdowns */ -.table-responsive { - overflow: visible !important; -} - -.table th { - background: var(--light-color); - border: none; - font-weight: 600; - color: var(--text-primary); - padding: 1.25rem 1rem; - text-transform: none; - font-size: 0.9rem; - letter-spacing: 0.3px; - border-bottom: 2px solid var(--border-color); -} - -.table td { - padding: 1.25rem 1rem; - border-bottom: 1px solid var(--border-color); - vertical-align: middle; - color: var(--text-secondary); -} -.table thead th, .table tbody td { white-space: normal; } - -.table tbody tr { - transition: var(--transition); -} - -.table tbody tr:hover { - background: var(--light-color); -} - -[data-theme="dark"] .table tbody tr:hover { - background: #111827; -} - -/* Consistent table action groups */ -.table td, -.table th { - vertical-align: middle; -} - -.actions-cell { - white-space: nowrap; -} - -.table td .btn-group { - display: inline-flex; - align-items: center; - flex-wrap: nowrap; -} - -/* Ensure grouped action buttons sit flush with no gaps */ -.btn-group > .btn, -.btn-group .btn-action { - margin: 0; -} -.btn-group > .btn + .btn, -.btn-group > .btn + .btn-group, -.btn-group > .btn-group + .btn, -.btn-group > .btn-group + .btn-group { - margin-left: -1px; /* collapse borders */ -} - -/* Enhanced form handling inside button groups */ -.btn-group > form { - display: inline-flex; - position: relative; - z-index: 1; -} - -/* Collapse borders between adjacent form-wrapped buttons */ -.btn-group > form + form { - margin-left: -1px; -} - -/* Form button styling within groups */ -.btn-group > form .btn { - border-radius: 0; - position: relative; - z-index: 1; -} - -/* First form button (left) */ -.btn-group > form:first-child .btn { - border-top-left-radius: var(--border-radius-sm); - border-bottom-left-radius: var(--border-radius-sm); - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -/* Middle form buttons */ -.btn-group > form:not(:first-child):not(:last-child) .btn { - border-radius: 0; -} - -/* Last form button (right) */ -.btn-group > form:last-child .btn { - border-top-right-radius: var(--border-radius-sm); - border-bottom-right-radius: var(--border-radius-sm); - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - -/* Single form button in group */ -.btn-group > form:only-child .btn { - border-radius: var(--border-radius-sm); -} - -/* Hover and focus states for form buttons in groups */ -.btn-group > form:hover { - z-index: 2; -} - -.btn-group > form .btn:focus { - z-index: 3; -} - -/* Enhanced button group styling for proper left/middle/right positioning */ -.btn-group .btn-action { - border-radius: 0; - position: relative; - z-index: 1; -} - -/* First button (left) */ -.btn-group .btn-action:first-child { - border-top-left-radius: var(--border-radius-sm); - border-bottom-left-radius: var(--border-radius-sm); - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -/* Middle buttons */ -.btn-group .btn-action:not(:first-child):not(:last-child) { - border-radius: 0; - margin-left: -1px; -} - -/* Last button (right) */ -.btn-group .btn-action:last-child { - border-top-right-radius: var(--border-radius-sm); - border-bottom-right-radius: var(--border-radius-sm); - border-top-left-radius: 0; - border-bottom-left-radius: 0; - margin-left: -1px; -} - -/* Single button in group (both first and last) */ -.btn-group .btn-action:only-child { - border-radius: var(--border-radius-sm); - margin-left: 0; -} - -/* Hover state management for grouped buttons */ -.btn-group .btn-action:hover { - z-index: 2; /* Bring hovered button to front */ -} - -/* Focus state for grouped buttons */ -.btn-group .btn-action:focus { - z-index: 3; -} - -.table td .btn-group .btn { - padding: 0.45rem 0.6rem; - font-size: 0.85rem; -} - -.table td .btn-group .btn i { - pointer-events: none; -} - -/* Restore contiguous button-group corners when custom .btn radius is applied */ -.btn-group > .btn:not(:last-child):not(.dropdown-toggle), -.btn-group > .btn-group:not(:last-child) > .btn { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -/* Enhanced Action Button System - Modern Styling */ -.btn-action { - padding: 0.5rem 0.75rem !important; - font-size: 0.875rem !important; - line-height: 1 !important; - background: var(--surface-color) !important; - border: 1px solid var(--gray-400) !important; - color: var(--gray-500) !important; - display: inline-flex !important; - align-items: center !important; - justify-content: center !important; - gap: 0.375rem !important; - transition: var(--transition-slow) !important; - border-radius: 0 !important; - min-width: 36px !important; - min-height: 36px !important; - position: relative !important; - overflow: hidden !important; - backdrop-filter: blur(8px) !important; - -webkit-backdrop-filter: blur(8px) !important; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05) !important; -} - -.btn-action::before { - content: ''; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(107, 114, 128, 0.1), transparent); - transition: left 0.5s; - pointer-events: none; -} - -.btn-action:hover::before { - left: 100%; -} - -.btn-action:hover { - background: var(--surface-hover) !important; - border-color: var(--gray-600) !important; - color: var(--gray-600) !important; - transform: translateY(-1px) !important; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important; -} - -.btn-action:focus { - box-shadow: 0 0 0 3px rgba(107, 114, 128, 0.1) !important; - outline: none !important; -} - -/* Dark theme action button adjustments */ -[data-theme="dark"] .btn-action { - background: var(--surface-color); - border-color: var(--text-muted); - color: var(--text-muted); - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); -} - -[data-theme="dark"] .btn-action:hover { - background: var(--surface-variant); - border-color: var(--text-secondary); - color: var(--text-secondary); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); - transform: translateY(-1px); -} - -[data-theme="dark"] .btn-action:focus { - box-shadow: var(--focus-ring), 0 1px 3px rgba(0, 0, 0, 0.3); -} - -/* All action button icons should match the border color for consistency */ -.btn-action i { - color: inherit; /* Icons inherit the button's text color, which matches the border */ -} - -/* All action button variants use consistent dark grey styling */ -.btn-action--view, -.btn-action--edit, -.btn-action--danger, -.btn-action--success, -.btn-action--warning, -.btn-action--more { - border-color: #6b7280; - color: #6b7280; -} - -.btn-action--view:hover, -.btn-action--edit:hover, -.btn-action--danger:hover, -.btn-action--success:hover, -.btn-action--warning:hover, -.btn-action--more:hover { - background: rgba(107, 114, 128, 0.1); - border-color: #4b5563; - color: #4b5563; -} - -/* Dark theme action button variants */ -[data-theme="dark"] .btn-action--view, -[data-theme="dark"] .btn-action--edit, -[data-theme="dark"] .btn-action--danger, -[data-theme="dark"] .btn-action--success, -[data-theme="dark"] .btn-action--warning, -[data-theme="dark"] .btn-action--more { - border-color: var(--text-muted); - color: var(--text-muted); - background: var(--surface-color); -} - -[data-theme="dark"] .btn-action--view:hover, -[data-theme="dark"] .btn-action--edit:hover, -[data-theme="dark"] .btn-action--danger:hover, -[data-theme="dark"] .btn-action--success:hover, -[data-theme="dark"] .btn-action--warning:hover, -[data-theme="dark"] .btn-action--more:hover { - background: var(--surface-variant); - border-color: var(--text-secondary); - color: var(--text-secondary); - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); -} - -/* Enhanced Button Group Styling - Square Corners */ -.btn-group .btn-action { - border-radius: 0 !important; - margin-left: -1px !important; - position: relative !important; - z-index: 1 !important; -} - -.btn-group .btn-action:first-child { - border-radius: 0 !important; - margin-left: 0 !important; -} - -.btn-group .btn-action:last-child { - border-radius: 0 !important; -} - -.btn-group .btn-action:only-child { - border-radius: 0 !important; -} - -.btn-group .btn-action:hover, -.btn-group .btn-action:focus { - z-index: 2; -} - -/* Ensure dropdown buttons in action groups follow dark grey styling */ -.btn-action.dropdown-toggle, -.btn-action.dropdown-toggle-split { - border-color: #6b7280 !important; - color: #6b7280 !important; - background: var(--surface-color) !important; -} - -.btn-action.dropdown-toggle:hover, -.btn-action.dropdown-toggle-split:hover, -.btn-action.dropdown-toggle:focus, -.btn-action.dropdown-toggle-split:focus { - border-color: #4b5563 !important; - color: #4b5563 !important; - background: rgba(107, 114, 128, 0.1) !important; -} - -.btn-action.dropdown-toggle.show, -.btn-action.dropdown-toggle-split.show { - border-color: #4b5563 !important; - color: #4b5563 !important; - background: rgba(107, 114, 128, 0.1) !important; -} - -/* Dark theme dropdown buttons */ -[data-theme="dark"] .btn-action.dropdown-toggle, -[data-theme="dark"] .btn-action.dropdown-toggle-split { - border-color: var(--text-muted) !important; - color: var(--text-muted) !important; - background: var(--surface-color) !important; -} - -[data-theme="dark"] .btn-action.dropdown-toggle:hover, -[data-theme="dark"] .btn-action.dropdown-toggle-split:hover, -[data-theme="dark"] .btn-action.dropdown-toggle:focus, -[data-theme="dark"] .btn-action.dropdown-toggle-split:focus, -[data-theme="dark"] .btn-action.dropdown-toggle.show, -[data-theme="dark"] .btn-action.dropdown-toggle-split.show { - border-color: var(--text-secondary) !important; - color: var(--text-secondary) !important; - background: var(--surface-variant) !important; - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); -} - -/* Icon styling and transitions */ -.btn-action i { - font-size: 0.95rem; - transition: color 0.2s ease; -} - -/* Hover effects are handled by the general action button styles above - removed duplicates */ - -.btn-group > .btn:nth-child(n+2), -.btn-group > .btn-group:nth-child(n+2) > .btn { - margin-left: -1px; -} - -.btn-group > .btn:not(:first-child), -.btn-group > .btn-group:not(:first-child) > .btn { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - -/* Badges and progress helpers */ -.badge-soft-primary { background: rgba(59,130,246,0.12); color: var(--primary-color); border: 1px solid rgba(59,130,246,0.25); } -.badge-soft-secondary { background: rgba(148,163,184,0.12); color: var(--text-secondary); border: 1px solid rgba(148,163,184,0.25); } -.badge-soft-success { background: rgba(34,197,94,0.12); color: #166534; border: 1px solid rgba(34,197,94,0.25); } -.badge-soft-danger { background: rgba(239,68,68,0.12); color: #991b1b; border: 1px solid rgba(239,68,68,0.25); } -.badge-pill { border-radius: 9999px; } - -.progress-thin { height: 6px; border-radius: 9999px; overflow: hidden; } -.progress-thin .progress-bar { border-radius: 9999px; } - -/* Enhanced Navigation Layout - Modern Glass Effect with Square Corners */ -.navbar { - background: var(--navbar-bg); - backdrop-filter: blur(20px); - -webkit-backdrop-filter: blur(20px); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(0, 0, 0, 0.06); - border-bottom: 1px solid var(--navbar-border); - padding: 0.75rem 0; - z-index: var(--z-fixed); - position: sticky; - top: 0; - min-height: var(--navbar-height); - transition: all var(--transition-slow); - border-radius: 0; -} - -/* Responsive navbar squeezes: hide labels earlier, keep icons and key controls */ -@media (max-width: 1199.98px) { /* < xl */ - .navbar .navbar-brand span { display: none !important; } - .navbar .nav-divider { display: none !important; } - .navbar .navbar-search { display: none !important; } -} - -@media (max-width: 991.98px) { /* < lg */ - .navbar .dropdown .dropdown-toggle .d-none.d-xl-inline { display: none !important; } -} - -/* Improve spacing of right-side controls on tight viewports */ -@media (max-width: 1199.98px) { - .navbar .navbar-nav.ms-auto > .nav-item { margin-left: .25rem; } -} - -/* Prevent overflow issues with longer localized labels */ -.navbar .container { - overflow: visible; -} - -/* Allow left nav items to consume available space; keep right group fixed */ -.navbar-nav.me-auto { flex: 1 1 auto; min-width: 0; } -.navbar-nav.ms-auto { flex: 0 0 auto; } - -/* Prevent wrapping on desktop; allow only at mobile sizes */ -.navbar-nav { flex-wrap: nowrap; row-gap: 0.25rem; column-gap: 0.25rem; background-color: transparent; border-radius: 0;} -.navbar-nav .nav-item { flex: 0 1 auto; min-width: 0; } - -/* Dark theme navbar styling */ -[data-theme="dark"] .navbar { - background: var(--navbar-bg) !important; - border-bottom-color: var(--border-color) !important; -} - -[data-theme="dark"] .navbar-collapse { - background: var(--navbar-bg) !important; -} -[data-theme="dark"] .navbar .navbar-toggler { - border-color: var(--border-color); -} -[data-theme="dark"] .navbar .navbar-toggler-icon { - filter: invert(1) brightness(0.9); -} -[data-theme="dark"] .navbar .nav-link { - color: var(--text-secondary) !important; -} -[data-theme="dark"] .navbar .nav-link.active { - color: var(--text-primary) !important; - background: var(--surface-variant) !important; -} -[data-theme="dark"] .navbar .nav-link:hover { - color: var(--primary-color) !important; - background: var(--surface-hover) !important; -} -[data-theme="dark"] .navbar .navbar-brand { - color: var(--primary-color) !important; -} -[data-theme="dark"] .navbar .navbar-brand .text-dark { - color: var(--text-primary) !important; -} -[data-theme="dark"] .mobile-tabbar { background: #0b1220; border-top: 1px solid var(--border-color); } - -/* Navbar shadow on scroll - Enhanced */ -.navbar.scrolled { - box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); - border-bottom-color: var(--border-strong); - background: var(--navbar-bg); - backdrop-filter: blur(16px); - -webkit-backdrop-filter: blur(16px); -} - -.navbar-brand { - font-weight: 700; - font-size: 1.5rem; - color: var(--primary-color) !important; - text-decoration: none; - transition: var(--transition); - display: flex; - align-items: center; - gap: 0.75rem; -} - -/* Prevent very long app names from breaking the layout */ -.navbar-brand span { - max-width: 220px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.navbar-brand img { - transition: var(--transition); -} - -.navbar-brand:hover img { - transform: scale(1.1); -} - -.navbar-brand:hover { - color: var(--primary-dark) !important; -} - -.navbar-nav .nav-link { - color: var(--text-secondary) !important; - font-weight: 500; - padding: 0.75rem 1rem; /* slightly tighter to reduce overflow */ - border-radius: 0; - transition: var(--transition); - position: relative; - margin: 0 0.25rem; - min-height: 52px; - display: flex; - align-items: center; - gap: 0.5rem; - white-space: nowrap; /* keep single label per link */ - overflow: hidden; /* enable ellipsis if needed */ - text-overflow: ellipsis; -} - -.navbar-nav .nav-link:hover { - color: #6b7280 !important; - background: var(--light-color); - transform: translateY(-1px); -} - -[data-theme="dark"] .navbar-nav .nav-link:hover { - background: #111827; -} - -.navbar-nav .nav-link.active { - background: #6b7280; - color: white !important; - box-shadow: 0 4px 12px rgba(107, 114, 128, 0.3); -} - -/* ========================================== - Density toggle (compact mode) - ========================================== */ -html.compact .card-body { padding: 0.75rem 1rem; } -html.compact .card-header { padding: 0.75rem 1rem; } -html.compact .card-footer { padding: 0.75rem 1rem; } -html.compact .btn { padding: 0.5rem 0.75rem; min-height: 40px; } -html.compact .table th, html.compact .table td { padding: 0.75rem; } -html.compact .form-control, html.compact .form-select { min-height: 44px; padding: 0.5rem 0.75rem; } -html.compact .navbar { min-height: calc(var(--navbar-height) - 12px); } - -/* Enhanced Mobile Layout */ -@media (max-width: 768px) { - .container { - padding-left: 1rem; - padding-right: 1rem; - } - - .section-spacing { - margin-bottom: var(--mobile-section-spacing); - } - - .card { - margin-bottom: var(--mobile-card-spacing); - } - - .card-body { - padding: 1.25rem; - } - - .card-header { - padding: 1.25rem 1.25rem; - } - - .btn { - padding: 1rem 1.5rem; - font-size: 1rem; - min-height: 52px; - width: 100%; - margin-bottom: 0.75rem; - } - - .btn:last-child { - margin-bottom: 0; - } - - .form-control, .form-select { - padding: 1rem 1.25rem; - font-size: 16px; - min-height: 56px; - } - - .table th, .table td { - padding: 1rem 0.75rem; - } - - .navbar { - padding: 0.75rem 0; - min-height: calc(var(--navbar-height) - 10px); - } - - .navbar-brand { - font-size: 1.25rem; - } - - .navbar-nav .nav-link { - padding: 1rem 1.5rem; - margin: 0.25rem 0; - font-size: 1.1rem; - min-height: var(--mobile-touch-target, 52px); - } -} - -/* Enhanced Small Mobile Layout */ -@media (max-width: 480px) { - .container { - padding-left: 0.75rem; - padding-right: 0.75rem; - } - - .card-body { - padding: 1rem; - } - - .card-header { - padding: 1rem 1rem; - } - - .btn { - padding: 1rem 1.25rem; - font-size: 0.95rem; - min-height: 56px; - } - - .form-control, .form-select { - padding: 0.875rem 1rem; - min-height: 56px; - } - - .navbar-brand { - font-size: 1.1rem; - } -} - -/* Enhanced Grid Layout */ -.row { - margin-left: -0.75rem; - margin-right: -0.75rem; -} - -.col, .col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12 { - padding-left: 0.75rem; - padding-right: 0.75rem; -} - -@media (max-width: 768px) { - .row { - margin-left: -0.5rem; - margin-right: -0.5rem; - } - - .col, .col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12 { - padding-left: 0.5rem; - padding-right: 0.5rem; - } -} - -/* Enhanced Typography */ -h1, h2, h3, h4, h5, h6 { - color: var(--text-primary); - font-weight: 700; - line-height: 1.3; - margin-bottom: 1rem; - letter-spacing: -0.02em; -} - -h1 { - font-size: 2.25rem; - font-weight: 800; - line-height: 1.2; -} - -h2 { - font-size: 1.875rem; - font-weight: 700; -} - -h3 { - font-size: 1.5rem; - font-weight: 700; -} - -h4 { - font-size: 1.25rem; - font-weight: 600; -} - -h5 { - font-size: 1.125rem; - font-weight: 600; -} - -h6 { - font-size: 1rem; - font-weight: 600; -} - -@media (max-width: 768px) { - h1 { font-size: 1.875rem; } - h2 { font-size: 1.625rem; } - h3 { font-size: 1.375rem; } - h4 { font-size: 1.125rem; } - h5 { font-size: 1rem; } - h6 { font-size: 0.95rem; } -} - -/* Enhanced Spacing Utilities */ -.section-gap { - margin-bottom: var(--section-spacing); -} - -.card-gap { - margin-bottom: var(--card-spacing); -} - -@media (max-width: 768px) { - .section-gap { - margin-bottom: var(--mobile-section-spacing); - } - - .card-gap { - margin-bottom: var(--mobile-card-spacing); - } -} - -/* Enhanced Animation Classes */ -.fade-in { - animation: fadeIn 0.4s ease-out; -} - -.slide-up { - animation: slideUp 0.4s ease-out; -} - -@keyframes fadeIn { - from { opacity: 0; } - to { opacity: 1; } -} - -@keyframes slideUp { - from { opacity: 0; transform: translateY(20px); } - to { opacity: 1; transform: translateY(0); } -} - -/* Enhanced Utility Classes */ -.text-gradient { - background: var(--bg-gradient); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -.glass-effect { - background: rgba(255, 255, 255, 0.9); - backdrop-filter: blur(15px); - border: 1px solid rgba(255, 255, 255, 0.3); -} - -.hover-lift { - transition: var(--transition); -} - -.hover-lift:hover { - transform: translateY(-4px); - box-shadow: var(--card-shadow-hover); - border-radius: var(--border-radius); /* Ensure border radius is maintained on hover */ -} - -/* Enhanced dropdown menu styling */ -.dropdown-menu { - background: var(--dropdown-bg); - -webkit-backdrop-filter: none; - backdrop-filter: none; - z-index: 1060 !important; - border: 1px solid var(--border-color); - border-radius: 12px !important; - box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15); - margin-top: 0.5rem; - overflow: visible !important; /* Allow outlines to show */ - position: absolute !important; - pointer-events: auto; - background-clip: padding-box; - min-width: 200px; - max-width: clamp(220px, 90vw, 360px); - padding: 0.75rem 0.25rem; /* Add padding to prevent outline clipping */ -} - -/* Ensure dropdowns in tables have proper stacking */ -.table .dropdown { - position: relative; - z-index: 1000; -} - -.table .dropdown.show { - z-index: 1100 !important; -} - -.table .dropdown-menu { - z-index: 1070 !important; -} - -/* Global fix for table overflow issues with dropdowns */ -.card .table-responsive, -.card-body .table-responsive { - overflow: visible !important; -} - -/* Specific cards that need overflow for dropdowns - safer approach */ -.card.shadow-sm { - overflow: visible !important; -} - -/* Dedicated navbar dropdown tweaks for better clarity */ -.navbar .dropdown-menu { - min-width: 220px; - border-radius: 12px !important; - padding: 0.75rem 0.25rem; /* Add padding to prevent outline clipping */ - position: absolute; /* allow Bootstrap popper to control */ - right: auto; - overflow: visible !important; /* Allow outlines to show */ -} -.navbar .dropdown-item { - padding: 0.75rem 1rem; -} - -/* Dark mode dropdown menu container */ -[data-theme="dark"] .dropdown-menu { - background: #0f172a !important; - border-color: var(--border-color); - box-shadow: 0 10px 25px rgba(0, 0, 0, 0.4); - border-radius: 12px !important; -} - -/* Dropdown items styling */ -.dropdown-item { - padding: 0.75rem 1rem; - margin: 0.125rem 0.25rem; /* Add margin for outline space */ - color: var(--text-primary); - transition: all 0.2s ease; - border: none; - background: transparent; - display: flex; - align-items: center; - font-weight: 500; - white-space: normal; /* allow wrapping for long translations */ - word-break: break-word; /* break long words/URLs if needed */ - hyphens: auto; /* hyphenate when possible */ - line-height: 1.25; - border-radius: 8px; /* Add border radius for better outline appearance */ -} - -.dropdown-item:hover { - background-color: var(--light-color); - color: var(--text-primary); - transform: translateX(4px); -} - -.dropdown-item:focus { - background-color: var(--light-color); - color: var(--text-primary); - outline: 2px solid var(--primary-color, #3b82f6); - outline-offset: 2px; - box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1); -} - -.dropdown-divider { - margin: 0.5rem 0; - border-color: var(--border-color); - opacity: 0.5; -} - -/* Dark mode dropdown items */ -[data-theme="dark"] .dropdown-item { - color: var(--text-secondary) !important; - border-bottom: 1px solid rgba(255,255,255,0.05); -} - -[data-theme="dark"] .dropdown-item:last-child { - border-bottom: none; -} - -[data-theme="dark"] .dropdown-item:hover { - background-color: #111827 !important; - color: var(--text-primary) !important; - transform: translateX(4px); -} - -[data-theme="dark"] .dropdown-item:focus { - background-color: #111827 !important; - color: var(--text-primary) !important; - outline: 2px solid var(--primary-color, #3b82f6); - outline-offset: 2px; - box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1); -} - -[data-theme="dark"] .dropdown-divider { - background-color: var(--border-color) !important; - opacity: 0.3; -} - -/* Light mode dropdown overrides */ -[data-theme="light"] .dropdown-menu { - background-color: var(--dropdown-bg) !important; - border: 1px solid var(--border-color); - box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); - border-radius: 12px !important; -} - -/* Ensure dropdowns inside cards stack above adjacent content */ -.card .dropdown, -.mobile-card .dropdown { - position: relative; - z-index: 2000; -} -.dropdown-item { - background-color: var(--dropdown-bg) !important; /* make items opaque */ -} -.dropdown-menu::before { - content: ""; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: var(--dropdown-bg); /* solid background to avoid transparency */ - border-radius: inherit; - z-index: -1; /* sit behind menu content but within menu stacking */ -} - -/* Fix white overlay in dark mode dropdown */ -[data-theme="dark"] .dropdown-menu::before { - background: #0f172a; -} - -/* Solid hover state for items to further avoid transparency feel */ -.dropdown-item:hover, .dropdown-item:focus { - background-color: var(--light-color) !important; -} - -/* Ensure input-group icons match input height */ -.input-group .input-group-text { - min-height: 52px; - display: inline-flex; - align-items: center; - border-radius: var(--border-radius-sm); -} - -/* Navbar search alignment and control sizing */ -.navbar .navbar-search-field { - display: flex; - align-items: center; - gap: 0.5rem; - height: 40px; - min-height: 40px; - padding: 0 0.75rem; - border: 1px solid var(--border-color); - border-radius: 10px; - background: var(--bs-body-bg, #fff); - box-shadow: inset 0 1px 0 rgba(0,0,0,0.03); -} -.navbar .navbar-search-field i { color: #9ca3af; } -.navbar .navbar-search-field input { - border: 0; - outline: none; - width: 100%; - height: 100%; - background: transparent; - color: var(--text-primary); -} -.navbar .navbar-search-field:focus-within { - border-color: var(--primary-color); - box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); -} -.navbar .nav-control { - height: 40px; - min-height: 40px; /* override btn min-height */ - display: inline-flex; - align-items: center; -} -.navbar .ms-auto > .nav-item { margin-left: 0.5rem; } -.navbar .ms-auto > .nav-item:first-child { margin-left: 0; } -.navbar .nav-divider { width: 1px; height: 24px; background: var(--border-color); opacity: 0.5; margin: 0 0.25rem; } - -/* Keep header on one line on desktop; constrain search width */ -@media (max-width: 991.98px) { - /* Permit wrapping on small screens to avoid overflow */ - .navbar .navbar-collapse { flex-wrap: wrap; } - .navbar .navbar-nav.me-auto { flex-wrap: wrap; row-gap: 0.25rem; } - .navbar .navbar-nav.ms-auto { flex: 0 1 auto; min-width: 0; align-items: center; column-gap: 0.25rem; row-gap: 0.25rem; flex-wrap: wrap; justify-content: flex-end; } - /* Search flexes but can shrink to fit */ - .navbar .navbar-search { flex: 1 1 220px; min-width: 180px; max-width: 320px; } -} - -/* Subtle active state with underline instead of pill */ -.navbar .navbar-nav .nav-link.active { - background: transparent; - color: var(--text-primary) !important; - box-shadow: none; -} -/* Only show underline on non-dropdown nav-links to avoid conflicting with Bootstrap's dropdown caret */ -.navbar .navbar-nav .nav-link.active:not(.dropdown-toggle)::after { - content: ""; - position: absolute; - left: 0.75rem; - right: 0.75rem; - bottom: 4px; - height: 2px; - background: var(--primary-color); - border-radius: 1px; -} -[data-theme="dark"] .navbar .navbar-nav .nav-link.active:not(.dropdown-toggle)::after { - background: var(--primary-color); -} - -/* Quiet navbar actions (icon-only) */ -.btn.btn-quiet, .nav-quiet { - background: transparent !important; - border: 1px solid var(--border-color) !important; - color: var(--text-secondary) !important; - transition: all 0.2s ease; -} -.btn.btn-quiet:hover, .nav-quiet:hover { - background: var(--light-color) !important; - color: var(--text-primary) !important; - border-color: var(--primary-color) !important; -} -.btn.btn-quiet:focus, .nav-quiet:focus { - box-shadow: 0 0 0 3px rgba(59,130,246,0.15) !important; -} - -/* Language switcher specific styles */ -#langDropdown { - padding: 0.5rem 0.75rem; - border-radius: 0.5rem; - min-height: 40px; - display: inline-flex; -} -#langDropdown .fa-globe { - font-size: 1.1rem; -} -#langDropdown + .dropdown-menu { - min-width: 180px; - margin-top: 0.5rem; -} -#langDropdown + .dropdown-menu .dropdown-header { - font-size: 0.75rem; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.5px; - color: var(--text-secondary); - padding: 0.5rem 1rem; -} -#langDropdown + .dropdown-menu .dropdown-item { - padding: 0.5rem 1rem; - transition: all 0.2s ease; - color: var(--text-primary); -} -#langDropdown + .dropdown-menu .dropdown-item.active { - background: rgba(59, 130, 246, 0.1); - color: var(--primary-color); - font-weight: 600; -} -#langDropdown + .dropdown-menu .dropdown-item.active .fa-check { - color: var(--primary-color); -} -#langDropdown + .dropdown-menu .dropdown-item:not(.active):hover { - background: var(--light-color); - color: var(--primary-color); -} -[data-theme="dark"] #langDropdown + .dropdown-menu .dropdown-item.active { - background: rgba(59, 130, 246, 0.15); - color: #60a5fa; -} -[data-theme="dark"] #langDropdown + .dropdown-menu .dropdown-item.active .fa-check { - color: #60a5fa; -} - -/* Backdrop to block interactions behind open dropdowns */ -/* Removed custom dropdown backdrop; rely on Bootstrap defaults */ - -/* Increase dropdown item touch targets and spacing */ -.dropdown-item { - padding: 0.6rem 1rem; - display: flex; - align-items: center; - gap: 0.5rem; -} - -.dropdown-item i { width: 1rem; text-align: center; flex: 0 0 auto; } - -/* Ensure user name in navbar doesn't overflow */ -.navbar .nav-item.dropdown .nav-link span { - max-width: 180px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -/* Prevent navbar from clipping dropdown outlines */ -.navbar { - overflow: visible !important; -} - -.navbar .container, -.navbar .container-fluid { - overflow: visible !important; -} - -/* Ensure dropdown containers have enough space for outlines */ -.navbar .nav-item.dropdown { - position: relative; - overflow: visible !important; -} - -/* Add padding to navbar to accommodate focus outlines */ -.navbar-nav { - padding: 0.25rem 0; -} - -/* Ensure dropdown toggle has space for focus outline */ -.navbar .dropdown-toggle { - margin: 0.125rem; -} - -/* Enhanced Mobile Components */ -.mobile-stack { - display: flex; - flex-direction: column; -} - -.mobile-stack .btn { - margin-bottom: 0.75rem; -} - -.mobile-stack .btn:last-child { - margin-bottom: 0; -} - -.touch-target { - min-height: 48px; - min-width: 48px; -} - -@media (max-width: 768px) { - .touch-target { - min-height: 52px; - min-width: 52px; - } -} - -/* Enhanced Footer Layout */ -.footer { - background: var(--bs-body-bg, #ffffff); - color: var(--text-secondary); - padding: 2.5rem 0; - margin-top: 4rem; - border-top: 1px solid var(--border-color); -} - -[data-theme="dark"] .footer { - background: #0b1220; -} - -.footer a { - color: var(--primary-color); - text-decoration: none; - transition: var(--transition); -} - -.footer a:hover { - color: var(--primary-dark); -} - -/* Enhanced Toast Container */ -.toast-container { - z-index: 9999; -} - -.toast { - border: 1px solid var(--border-color); - border-radius: var(--border-radius-sm); - box-shadow: var(--card-shadow-hover); -} - -/* Enhanced Loading Animation */ -.loading-spinner { - display: inline-block; - width: 20px; - height: 20px; - border: 2px solid rgba(255, 255, 255, 0.3); - border-radius: 50%; - border-top-color: white; - animation: spin 1s ease-in-out infinite; -} - -/* Skeleton loader utility */ -.skeleton { - display: inline-block; - background: linear-gradient(90deg, #f3f4f6 25%, #e5e7eb 50%, #f3f4f6 75%); - background-size: 200% 100%; - animation: skeleton-loading 1.5s infinite; - border-radius: 8px; -} - -@keyframes skeleton-loading { - 0% { background-position: 200% 0; } - 100% { background-position: -200% 0; } -} - -@keyframes spin { - to { transform: rotate(360deg); } -} - -/* Enhanced Modal Layout */ -.modal-content { - border: 1px solid var(--border-color); - border-radius: var(--border-radius-lg); - overflow: hidden; /* ensure rounded corners render on all sides */ - box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25), 0 10px 20px -5px rgba(0, 0, 0, 0.1); - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); -} - -.modal-header { - border-bottom: 1px solid var(--border-color); - padding: 1.75rem; - border-top-left-radius: var(--border-radius); - border-top-right-radius: var(--border-radius); - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; -} - -.modal-body { - padding: 1.75rem; -} - -.modal-footer { - border-top: 1px solid var(--border-color); - padding: 1.75rem; - border-bottom-left-radius: var(--border-radius); - border-bottom-right-radius: var(--border-radius); - border-top-left-radius: 0; - border-top-right-radius: 0; -} - -@media (max-width: 576px) { - .modal-dialog { - margin: 0.75rem; - max-width: calc(100% - 1.5rem); - } - - .modal-header, .modal-body, .modal-footer { - padding: 1.25rem; - } -} - -/* Enhanced Badge Layout */ -.badge { - font-size: 0.8rem; - font-weight: 500; - padding: 0.5rem 0.875rem; - border-radius: var(--border-radius-sm); -} - -/* Enhanced Alert Layout */ -.alert { - border: 1px solid var(--border-color); - border-radius: var(--border-radius); - padding: 1rem 1.25rem; - font-weight: 500; - position: relative; - background: var(--bs-card-bg, #ffffff); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); - display: flex; - align-items: flex-start; - gap: 0.75rem; - animation: slideDown 0.4s cubic-bezier(0.16, 1, 0.3, 1); -} - -@keyframes slideDown { - from { - opacity: 0; - transform: translateY(-10px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -[data-theme="dark"] .alert { background: #0f172a; } -[data-theme="dark"] .alert-success { background: #052e1f; color: #a7f3d0; } -[data-theme="dark"] .alert-danger { background: #3f1d1d; color: #fecaca; } -[data-theme="dark"] .alert-info { background: #082f49; color: #bae6fd; } -[data-theme="dark"] .alert-warning { background: #422006; color: #fed7aa; } - -/* ========================================== - Dark theme utility & component overrides - ========================================== */ - -/* Text utilities */ -[data-theme="dark"] .text-dark { color: var(--text-primary) !important; } -[data-theme="dark"] .text-muted { color: var(--text-muted) !important; } -[data-theme="dark"] .text-secondary { color: var(--text-secondary) !important; } - -/* Background utilities */ -[data-theme="dark"] .bg-white { background-color: #0f172a !important; } -[data-theme="dark"] .bg-light { background-color: #111827 !important; } -[data-theme="dark"] .bg-body { background-color: #0b1220 !important; } - -/* Borders and dividers */ -[data-theme="dark"] .border, -[data-theme="dark"] .border-top, -[data-theme="dark"] .border-bottom, -[data-theme="dark"] .border-start, -[data-theme="dark"] .border-end, -[data-theme="dark"] hr, -[data-theme="dark"] .dropdown-divider { border-color: var(--border-color) !important; } - -/* List groups */ -[data-theme="dark"] .list-group-item { - background-color: #0f172a; - color: var(--text-secondary); - border-color: var(--border-color); -} -[data-theme="dark"] .list-group-item.active { - background-color: var(--primary-color); - color: #ffffff; - border-color: var(--primary-dark); -} - -/* Badges */ -[data-theme="dark"] .badge.bg-light { - background-color: #1f2937 !important; - color: var(--text-secondary) !important; - border: 1px solid var(--border-color); -} - -/* Pagination */ -[data-theme="dark"] .pagination .page-link { - background-color: #0f172a; - color: var(--text-secondary); - border-color: var(--border-color); -} -[data-theme="dark"] .pagination .page-item.active .page-link { - background-color: var(--primary-color); - color: #ffffff; - border-color: var(--primary-dark); -} -[data-theme="dark"] .pagination .page-link:hover { - background-color: #111827; -} - -/* Tables: ensure caption and muted text are readable */ -[data-theme="dark"] table caption { color: var(--text-muted); } - -/* Inputs toggles and checks */ -[data-theme="dark"] .form-check-input:checked { - background-color: var(--primary-color); - border-color: var(--primary-color); -} - -/* Enhanced status badges for dark mode */ -[data-theme="dark"] .status-todo { - background: linear-gradient(135deg, #334155 0%, #475569 100%) !important; - color: #cbd5e1 !important; - border: 1px solid #64748b !important; -} -[data-theme="dark"] .status-in_progress { - background: linear-gradient(135deg, #451a03 0%, #78350f 100%) !important; - color: #fbbf24 !important; - border: 1px solid #f59e0b !important; -} -[data-theme="dark"] .status-review { - background: linear-gradient(135deg, #1e3a8a 0%, #3730a3 100%) !important; - color: #dbeafe !important; - border: 1px solid #3b82f6 !important; -} -[data-theme="dark"] .status-done { - background: linear-gradient(135deg, #064e3b 0%, #065f46 100%) !important; - color: #d1fae5 !important; - border: 1px solid #10b981 !important; -} -[data-theme="dark"] .status-cancelled { - background: linear-gradient(135deg, #7f1d1d 0%, #991b1b 100%) !important; - color: #fee2e2 !important; - border: 1px solid #ef4444 !important; -} - -/* Priority badges for dark mode */ -[data-theme="dark"] .priority-low { - background: linear-gradient(135deg, #064e3b 0%, #065f46 100%) !important; - color: #d1fae5 !important; - border: 1px solid #10b981 !important; -} -[data-theme="dark"] .priority-medium { - background: linear-gradient(135deg, #451a03 0%, #78350f 100%) !important; - color: #fbbf24 !important; - border: 1px solid #f59e0b !important; -} -[data-theme="dark"] .priority-high { - background: linear-gradient(135deg, #9a3412 0%, #c2410c 100%) !important; - color: #fed7aa !important; - border: 1px solid #fd7e14 !important; -} -[data-theme="dark"] .priority-urgent { - background: linear-gradient(135deg, #7f1d1d 0%, #991b1b 100%) !important; - color: #fee2e2 !important; - border: 1px solid #dc3545 !important; -} - -/* Task detail styling for dark mode */ -[data-theme="dark"] .payment-detail .detail-label { - color: var(--text-muted) !important; -} -[data-theme="dark"] .payment-detail .detail-value { - color: var(--text-secondary) !important; -} -[data-theme="dark"] .section-title { - color: var(--text-primary) !important; - border-bottom-color: var(--primary-color) !important; -} -[data-theme="dark"] .client-details .client-name { - color: var(--text-primary) !important; -} - -/* Fix hardcoded priority colors in templates for dark mode */ -[data-theme="dark"] .priority-low[style*="background-color: #28a745"] { - background: linear-gradient(135deg, #064e3b 0%, #065f46 100%) !important; - color: #d1fae5 !important; - border: 1px solid #10b981 !important; -} - -[data-theme="dark"] .priority-medium[style*="background-color: #ffc107"] { - background: linear-gradient(135deg, #451a03 0%, #78350f 100%) !important; - color: #fbbf24 !important; - border: 1px solid #f59e0b !important; -} - -[data-theme="dark"] .priority-high[style*="background-color: #fd7e14"] { - background: linear-gradient(135deg, #9a3412 0%, #c2410c 100%) !important; - color: #fed7aa !important; - border: 1px solid #fd7e14 !important; -} - -[data-theme="dark"] .priority-urgent[style*="background-color: #dc3545"] { - background: linear-gradient(135deg, #7f1d1d 0%, #991b1b 100%) !important; - color: #fee2e2 !important; - border: 1px solid #dc3545 !important; -} - -/* Fix any hardcoded dark backgrounds */ -[data-theme="dark"] [style*="background: #1f2a44"] { - background: var(--surface-variant) !important; - color: var(--text-primary) !important; -} - -/* Enhanced button focus states for dark mode */ -[data-theme="dark"] .btn:focus { - outline: none; - box-shadow: var(--focus-ring); -} - -[data-theme="dark"] .btn:focus:not(:focus-visible) { - box-shadow: none; -} - -[data-theme="dark"] .btn:focus-visible { - box-shadow: var(--focus-ring); -} - -/* Ensure button text is always readable in dark mode */ -[data-theme="dark"] .btn { - color: var(--text-primary); - border-color: var(--border-color); -} - -[data-theme="dark"] .btn:hover { - color: var(--text-primary); -} - -/* Badge improvements for dark mode */ -[data-theme="dark"] .badge { - border: 1px solid rgba(255, 255, 255, 0.1); -} - -[data-theme="dark"] .badge.bg-primary { - background: var(--primary-color) !important; - color: var(--text-on-primary) !important; -} - -[data-theme="dark"] .badge.bg-success { - background: var(--success-color) !important; - color: var(--text-on-primary) !important; -} - -[data-theme="dark"] .badge.bg-danger { - background: var(--danger-color) !important; - color: var(--text-on-primary) !important; -} - -[data-theme="dark"] .badge.bg-warning { - background: var(--warning-color) !important; - color: var(--text-on-primary) !important; -} - -[data-theme="dark"] .badge.bg-info { - background: var(--info-color) !important; - color: var(--text-on-primary) !important; -} - -[data-theme="dark"] .badge.bg-secondary { - background: var(--text-muted) !important; - color: var(--surface-color) !important; -} - -.alert-success { - border-color: #10b981; - background: #f0fdf4; - color: #065f46; -} - -.alert-danger { - border-color: #ef4444; - background: #fef2f2; - color: #991b1b; -} - -.alert-info { - border-color: #06b6d4; - background: #f0f9ff; - color: #0c4a6e; -} - -.alert-warning { - border-color: #f59e0b; - background: #fffbeb; - color: #92400e; -} - -/* Enhanced Timer Display */ -.timer-display { - font-family: 'Inter', monospace; - font-size: 2rem; - font-weight: 700; - color: var(--primary-color); - letter-spacing: 2px; -} - -@media (max-width: 768px) { - .timer-display { - font-size: 1.75rem; - letter-spacing: 1px; - } -} - -/* Enhanced Stats Cards */ -.stats-card { - background: var(--bg-gradient); - color: white; - position: relative; - overflow: hidden; -} - -.stats-card .card-body { - position: relative; - z-index: 1; -} - -.stats-card i { - font-size: 2.5rem; - opacity: 0.9; - margin-bottom: 1rem; -} - -/* Ensure header subtitle text is white within stats-card headers */ -.stats-card .text-muted, -.stats-card p { - color: rgba(255, 255, 255, 0.9) !important; -} -.stats-card h1, .stats-card .h1, -.stats-card h2, .stats-card .h2, -.stats-card h3, .stats-card .h3 { - color: #ffffff !important; -} - -/* Header action buttons on stats cards: low opacity default, high on hover */ -.stats-card .btn-header { - color: rgba(255, 255, 255, 0.9); - border-color: rgba(255, 255, 255, 0.45); - background: transparent; - opacity: 0.85; -} -.stats-card .btn-header:hover { - opacity: 1; - color: #ffffff; - border-color: rgba(255, 255, 255, 0.9); - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(255, 255, 255, 0.15); -} -.stats-card .btn-header i { color: inherit; } - -.stats-card h4 { - font-size: 2.25rem; - font-weight: 700; - margin-bottom: 0.75rem; -} - -@media (max-width: 768px) { - .stats-card h4 { - font-size: 2rem; - } - - .stats-card i { - font-size: 2rem; - margin-bottom: 0.75rem; - } -} - -/* Enhanced Custom Scrollbar */ -::-webkit-scrollbar { - width: 8px; -} - -::-webkit-scrollbar-track { - background: var(--light-color); -} - -::-webkit-scrollbar-thumb { - background: var(--border-color); - border-radius: var(--border-radius); -} - -::-webkit-scrollbar-thumb:hover { - background: var(--text-muted); -} - -/* ========================================== - Global Accessibility & Motion Preferences - ========================================== */ - -/* Visible focus outlines (keyboard / a11y) */ -.btn:focus, -.form-control:focus, -.form-select:focus, -.nav-link:focus, -.dropdown-item:focus { - outline: 2px solid #6b7280; - outline-offset: 2px; -} - -/* High-contrast user preference support */ -@media (prefers-contrast: high) { - .card, - .btn, - .table td, - .dropdown-menu { - border-width: 2px; - border-color: #000 !important; - } - .dropdown-item { - color: #000 !important; - border-bottom: 1px solid #000; - } - .dropdown-item:hover { - background: #000 !important; - color: #fff !important; - } - .dropdown-divider { border-top: 2px solid #000 !important; } -} - -/* Reduced-motion user preference */ -@media (prefers-reduced-motion: reduce) { - *, *::before, *::after { - animation-duration: 0.001s !important; - animation-iteration-count: 1 !important; - transition-duration: 0.001s !important; - scroll-behavior: auto !important; - } - .fade-in, - .slide-up, - .mobile-fade-in, - .mobile-slide-up { - animation: none !important; - } -} - - -/* Shared summary cards used across pages (invoices, reports) */ -.summary-card { - border-radius: 12px; - cursor: default; -} - -.summary-icon { - width: 48px; - height: 48px; - border-radius: 12px; - display: flex; - align-items: center; - justify-content: center; - font-size: 20px; -} - -.summary-label { - font-size: 12px; - font-weight: 600; - color: var(--text-secondary); - text-transform: uppercase; - letter-spacing: 0.5px; - margin-bottom: 4px; -} - -.summary-value { - font-size: 20px; - font-weight: 700; - color: var(--text-primary); -} - -.empty-state { - padding: 2rem; -} - -.empty-state i { - opacity: 0.5; -} - -@media (max-width: 768px) { - .summary-card { margin-bottom: 1rem; } - .summary-value { font-size: 18px; } -} - -/* Shared page header utilities to align with admin dashboard */ -.page-header { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 1.5rem; -} - -.page-header .h3 { margin: 0; } - -/* ========================================== - Prettier Header Buttons (page/card/modal headers) - ========================================== */ -.card-header .btn, -.page-header .btn, -.modal-header .btn { - padding: 0.5rem 1rem; - font-size: 0.875rem; - font-weight: 500; - border-radius: 8px; - border: 1px solid var(--border-color); - background: linear-gradient(180deg, #ffffff, #f8fafc); - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06); - transition: var(--transition); -} - -.card-header .btn:hover, -.page-header .btn:hover, -.modal-header .btn:hover { - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); -} - -.card-header .btn.btn-outline-primary, -.page-header .btn.btn-outline-primary, -.modal-header .btn.btn-outline-primary { - background: transparent; - color: #6b7280; - border-color: #6b7280; -} - -.card-header .btn.btn-outline-primary:hover, -.page-header .btn.btn-outline-primary:hover, -.modal-header .btn.btn-outline-primary:hover { - background: #f9fafb; - color: #4b5563; - border-color: #4b5563; - box-shadow: 0 4px 12px rgba(107, 114, 128, 0.15); -} - -.card-header .btn i, -.page-header .btn i, -.modal-header .btn i { - margin-right: 0.375rem; -} - -/* Add small spacing after icons in regular buttons (avoid icon-only/header buttons) */ -.btn:not(.btn-icon):not(.btn-header) i { - margin-right: 0.375rem; -} - -/* Button icon color fixes for dark mode */ -[data-theme="dark"] .btn i { - color: inherit; -} - -[data-theme="dark"] .btn-primary i, -[data-theme="dark"] .btn-success i, -[data-theme="dark"] .btn-danger i, -[data-theme="dark"] .btn-warning i, -[data-theme="dark"] .btn-info i, -[data-theme="dark"] .btn-secondary i { - color: var(--text-on-primary); -} - -[data-theme="dark"] .btn-outline-primary i { - color: var(--primary-color); -} - -[data-theme="dark"] .btn-outline-secondary i { - color: var(--text-muted); -} - -[data-theme="dark"] .btn-outline-success i { - color: var(--success-color); -} - -[data-theme="dark"] .btn-outline-danger i { - color: var(--danger-color); -} - -[data-theme="dark"] .btn-outline-warning i { - color: var(--warning-color); -} - -[data-theme="dark"] .btn-outline-info i { - color: var(--info-color); -} - -[data-theme="dark"] .btn-outline-light i { - color: var(--text-secondary); -} - -/* Navbar dark mode fixes */ -[data-theme="dark"] .navbar-nav .nav-link { - color: var(--text-secondary) !important; -} - -[data-theme="dark"] .navbar-nav .nav-link:hover { - color: var(--primary-color) !important; - background: rgba(96, 165, 250, 0.1); -} - -[data-theme="dark"] .navbar-nav .nav-link.active { - background: var(--primary-color); - color: var(--text-on-primary) !important; - box-shadow: 0 4px 12px rgba(96, 165, 250, 0.3); -} - -/* Consistent badge sizing used next to page titles */ -.badge.fs-6 { - line-height: 1; - padding: 0.5rem 0.75rem; - border-radius: 9999px; -} - -/* Tooltip overrides to keep light tooltips in dark mode */ -[data-theme="dark"] .tooltip .tooltip-inner { - background-color: #f9fafb; /* light */ - color: #111827; /* dark text */ - border: 1px solid rgba(0,0,0,0.1); -} -[data-theme="dark"] .tooltip.bs-tooltip-top .tooltip-arrow::before, -[data-theme="dark"] .tooltip.bs-tooltip-auto[data-popper-placement^="top"] .tooltip-arrow::before { - border-top-color: #f9fafb; -} -[data-theme="dark"] .tooltip.bs-tooltip-bottom .tooltip-arrow::before, -[data-theme="dark"] .tooltip.bs-tooltip-auto[data-popper-placement^="bottom"] .tooltip-arrow::before { - border-bottom-color: #f9fafb; -} -[data-theme="dark"] .tooltip.bs-tooltip-start .tooltip-arrow::before, -[data-theme="dark"] .tooltip.bs-tooltip-auto[data-popper-placement^="left"] .tooltip-arrow::before { - border-left-color: #f9fafb; -} -[data-theme="dark"] .tooltip.bs-tooltip-end .tooltip-arrow::before, -[data-theme="dark"] .tooltip.bs-tooltip-auto[data-popper-placement^="right"] .tooltip-arrow::before { - border-right-color: #f9fafb; -} - -/* ========================================== - Consistent Navbar Height (Desktop) - ========================================== */ -@media (min-width: 992px) { - .navbar { - height: var(--navbar-height); - padding-top: 0; - padding-bottom: 0; - } - .navbar .container { - height: var(--navbar-height); - display: flex; - align-items: center; - } - /* Slightly tighter spacing on dense labels */ - .navbar-nav .nav-link { padding: 0.7rem 1rem; } -} - -/* ========================================== - Comments System Styles - ========================================== */ -.comments-section { - position: relative; -} - -.comments-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 1.5rem; - min-height: 2.5rem; -} - -.comments-header h6 { - display: flex; - align-items: center; - margin: 0; - gap: 0.5rem; -} - -.comments-header .badge { - vertical-align: middle; - margin-left: 0.5rem; -} - -/* Add a bit of space between the counter and the action button */ -.comments-header > .btn { - margin-left: 0.75rem; -} - -/* Neutralize nested cards inside the comments list to avoid double borders/padding */ -.comments-list .card { - background: transparent; - border: 0; - box-shadow: none; -} -.comments-list .card-body { - padding: 0; -} - -.comment { - position: relative; - margin-bottom: 1.5rem; - padding: 1.5rem; - border-radius: 12px; - background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%); - border: 1px solid #e2e8f0; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); -} - -.comment:hover { - transform: translateY(-2px); - box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1); - border-color: var(--primary-color); -} - -.comment-header { - display: flex; - align-items: center; - margin-bottom: 1rem; - gap: 0.75rem; - justify-content: flex-start; - flex-wrap: nowrap; -} - -.comment-avatar .avatar-circle { - width: 44px; - height: 44px; - border-radius: 50%; - background: linear-gradient(135deg, var(--primary-color) 0%, #3b82f6 100%); - color: white; - display: flex; - align-items: center; - justify-content: center; - font-weight: 700; - font-size: 1.1rem; - flex-shrink: 0; - box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3); - border: 2px solid rgba(255, 255, 255, 0.2); -} - -.comment-meta { - flex: 1 1 auto; - min-width: 0; -} - -.comment-author { - font-weight: 700; - color: var(--text-primary); - margin-bottom: 0.5rem; - font-size: 0.95rem; - display: flex; - align-items: center; - gap: 0.75rem; -} - -.comment-author .badge { - font-size: 0.7rem; - padding: 0.25rem 0.5rem; - border-radius: 12px; - font-weight: 600; - margin-left: 0.25rem; -} - -.comment-timestamp { - font-size: 0.8rem; - color: var(--text-muted); - display: flex; - align-items: center; - gap: 0.5rem; - line-height: 1.4; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.comment-timestamp i { - font-size: 0.75rem; - opacity: 0.7; -} - -.comment-actions { - display: flex; - gap: 0.25rem; - opacity: 1; - transition: all 0.2s ease; - margin-top: 0.25rem; - flex: 0 0 auto; -} - -.comment:hover .comment-actions { opacity: 1; } - -/* Push action buttons to the far right while keeping meta flexible */ -.comment-actions { margin-left: auto; } - -.comment-actions .btn { - padding: 0.375rem 0.5rem; - font-size: 0.75rem; - border-radius: 8px; - transition: all 0.2s ease; -} - -.comment-actions .btn:hover { - transform: translateY(-1px); - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); -} - -.comment-content { - margin-left: 0; - padding-left: 3.5rem; - position: relative; - margin-top: 0.5rem; -} - -/* Removed decorative guideline to prevent double left bar next to .comment-text */ - -.comment-text { - color: var(--text-primary); - line-height: 1.7; - white-space: pre-wrap; - word-wrap: break-word; - word-break: break-word; - overflow-wrap: break-word; - font-size: 0.9rem; - background: rgba(59, 130, 246, 0.02); - padding: 1rem 1.25rem; - border-radius: 8px; - border-left: 3px solid var(--primary-color); - margin: 0; - position: relative; -} - -.comment-text::before { - content: ''; - position: absolute; - left: -3px; - top: 0; - bottom: 0; - width: 3px; - background: var(--primary-color); - border-radius: 0 2px 2px 0; -} - -/* Ensure all other comment elements have normal text flow */ -.comment, -.comment-header, -.comment-meta, -.comment-author, -.comment-timestamp, -.comment-actions, -.comment-content, -.comment-edit-form, -.comment-reply-form { - white-space: normal !important; -} - -/* Avoid over-aggressive resets that broke flex layouts in headers/actions */ - -/* Ensure only comment text preserves line breaks */ -.comment-text { - white-space: pre-wrap !important; -} - -/* Additional specific fixes for comment metadata */ -.comment-author, -.comment-timestamp, -.comment-timestamp time, -.comment-timestamp span { - white-space: normal; -} - -.comment-edit-form, -.comment-reply-form { - margin-left: 3.5rem; - margin-top: 1rem; - padding: 1rem; - background: rgba(59, 130, 246, 0.03); - border-radius: 8px; - border: 1px solid rgba(59, 130, 246, 0.1); -} - -.comment-replies { - margin-left: 2rem; - padding-left: 1.5rem; - border-left: 3px solid #e2e8f0; - position: relative; - margin-top: 1rem; -} - -.comment-replies::before { - content: ''; - position: absolute; - left: -1.5px; - top: 0; - width: 3px; - height: 20px; - background: linear-gradient(180deg, var(--primary-color) 0%, transparent 100%); - border-radius: 0 0 2px 2px; -} - -.comment-reply { - margin-bottom: 1rem; - position: relative; -} - -.comment-reply:last-child { - margin-bottom: 0; -} - -.comment-reply .comment { - background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%); - border: 1px solid #e2e8f0; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03); -} - -.comment-reply .comment:hover { - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); -} - -.new-comment-form { - margin-bottom: 2rem; - padding: 1.5rem; - background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%); - border-radius: 12px; - border: 2px dashed #e2e8f0; - transition: all 0.3s ease; -} - -.new-comment-form:hover { - border-color: var(--primary-color); - background: linear-gradient(135deg, #ffffff 0%, #f0f9ff 100%); -} - -.no-comments { - padding: 4rem 2rem; - text-align: center; - color: var(--text-muted); - background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%); - border-radius: 12px; - border: 2px dashed #e2e8f0; -} - -.no-comments .fas { - font-size: 3rem; - opacity: 0.3; - margin-bottom: 1rem; - display: block; -} - -/* Comment form styling */ -.comment-form textarea { - resize: vertical; - min-height: 120px; - transition: all 0.3s ease; - border: 2px solid #e2e8f0; - border-radius: 8px; - padding: 0.75rem 1rem; - font-size: 0.9rem; - line-height: 1.6; -} - -.comment-form textarea:focus { - border-color: var(--primary-color); - box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); - outline: none; -} - -.comment-form .btn { - border-radius: 8px; - font-weight: 600; - padding: 0.5rem 1rem; - transition: all 0.2s ease; -} - -.comment-form .btn:hover { - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); -} - -/* Dark theme adjustments */ -[data-theme="dark"] .comment { - background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%); - border-color: #334155; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); -} - -[data-theme="dark"] .comment:hover { - border-color: var(--primary-color); - box-shadow: 0 8px 25px rgba(0, 0, 0, 0.4); - transform: translateY(-2px); -} - -[data-theme="dark"] .comment-avatar .avatar-circle { - background: linear-gradient(135deg, var(--primary-color) 0%, #1d4ed8 100%); - box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4); -} - -[data-theme="dark"] .comment-text { - background: rgba(59, 130, 246, 0.05); - border-left-color: var(--primary-color); -} - -[data-theme="dark"] .comment-replies { - border-left-color: #334155; -} - -[data-theme="dark"] .comment-reply .comment { - background: linear-gradient(135deg, #1e293b 0%, #334155 100%); - border-color: #475569; -} - -[data-theme="dark"] .new-comment-form { - background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%); - border-color: #334155; -} - -[data-theme="dark"] .new-comment-form:hover { - border-color: var(--primary-color); - background: linear-gradient(135deg, #0f172a 0%, #1e3a8a 100%); -} - -[data-theme="dark"] .no-comments { - background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%); - border-color: #334155; -} - -[data-theme="dark"] .comment-edit-form, -[data-theme="dark"] .comment-reply-form { - background: rgba(59, 130, 246, 0.08); - border-color: rgba(59, 130, 246, 0.2); -} - -[data-theme="dark"] .comment-form textarea { - background: #1e293b; - border-color: #334155; - color: #e2e8f0; -} - -[data-theme="dark"] .comment-form textarea:focus { - border-color: var(--primary-color); - box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2); - background: #0f172a; -} - -/* Mobile responsiveness */ -@media (max-width: 768px) { - .comment { - margin-bottom: 1rem; - padding: 1.25rem; - border-radius: 8px; - } - - .comment-header { - gap: 0.5rem; - align-items: flex-start; - } - - .comment-avatar .avatar-circle { - width: 36px; - height: 36px; - font-size: 0.9rem; - } - - .comment-content { - padding-left: 2.75rem; - margin-top: 0.25rem; - } - - .comment-content::before { - left: 1rem; - top: -0.25rem; - } - - .comment-replies { - margin-left: 1rem; - padding-left: 1rem; - border-left-width: 2px; - } - - .comment-edit-form, - .comment-reply-form { - margin-left: 2.75rem; - padding: 0.75rem; - } - - .comment-actions { - opacity: 1; /* Always show on mobile */ - gap: 0.5rem; - } - - .comment-actions .btn { - padding: 0.5rem 0.75rem; - font-size: 0.8rem; - } - - .new-comment-form { - padding: 1rem; - margin-bottom: 1.5rem; - } - - .no-comments { - padding: 2rem 1rem; - } - - .no-comments .fas { - font-size: 2rem; - } - - .comment-text { - font-size: 0.85rem; - padding: 0.75rem 1rem; - } - - .comment-author { - margin-bottom: 0.25rem; - gap: 0.5rem; - } -} - -/* Additional animations and effects */ -.comment-item { - animation: slideInComment 0.4s cubic-bezier(0.4, 0, 0.2, 1); -} - -@keyframes slideInComment { - from { - opacity: 0; - transform: translateY(20px) scale(0.95); - } - to { - opacity: 1; - transform: translateY(0) scale(1); - } -} - -/* Hover effects for better interactivity */ -.comment-avatar .avatar-circle { - transition: all 0.3s ease; -} - -.comment:hover .comment-avatar .avatar-circle { - transform: scale(1.05); - box-shadow: 0 6px 16px rgba(59, 130, 246, 0.4); -} - -/* Loading states */ -.comment-form .btn:disabled { - opacity: 0.6; - cursor: not-allowed; - transform: none !important; -} - -.comment-form .btn:disabled:hover { - transform: none !important; - box-shadow: none !important; -} - -/* Animation for new comments */ -@keyframes slideInComment { - from { - opacity: 0; - transform: translateY(-10px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -.comment-item { - animation: slideInComment 0.3s ease-out; -} - -/* Loading spinner for forms */ -.spinner-border-sm { - width: 1rem; - height: 1rem; - border-width: 0.1em; -} - -/* Modal z-index fix for comments */ -#deleteCommentModal { - z-index: 1060 !important; -} - -#deleteCommentModal .modal-backdrop { - z-index: 1055 !important; -} - -/* Ensure modal is clickable */ -#deleteCommentModal .modal-dialog { - pointer-events: auto; -} - -/* Modal z-index fix for task quick view */ -#taskQuickViewModal { - z-index: 1056 !important; -} - -/* Ensure modal dialog is above backdrop and clickable */ -#taskQuickViewModal .modal-dialog { - pointer-events: auto !important; - z-index: 1057 !important; -} - -/* Ensure all modal content is interactive */ -#taskQuickViewModal .modal-content { - pointer-events: auto !important; -} - -/* Global modal fixes to prevent interaction issues */ -.modal.show { - display: block !important; -} - -.modal-backdrop { - z-index: 1040 !important; -} - -.modal { - z-index: 1050 !important; -} - -.modal-dialog { - pointer-events: auto !important; -} - -/* ===== MODERN UI ENHANCEMENTS ===== */ - -/* Enhanced Navigation */ -.navbar { - background: var(--navbar-bg); - backdrop-filter: blur(10px); - border-bottom: 1px solid var(--border-color); - padding: 0.75rem 0; - transition: var(--transition); -} - -.navbar.scrolled { - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08); - background: rgba(255, 255, 255, 0.98); -} - -[data-theme="dark"] .navbar.scrolled { - background: rgba(11, 18, 32, 0.98); - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4), 0 2px 8px rgba(0, 0, 0, 0.3); -} - -.navbar-brand { - font-weight: var(--font-weight-bold); - color: var(--text-primary) !important; - display: flex; - align-items: center; - gap: 0.75rem; - transition: var(--transition); -} - -.navbar-brand:hover { - transform: translateY(-1px); -} - -.nav-link { - color: var(--text-secondary) !important; - font-weight: var(--font-weight-medium); - padding: 0.75rem 1rem !important; - border-radius: var(--border-radius-xs); - transition: var(--transition); - position: relative; -} - -.nav-link:hover, -.nav-link.active { - color: var(--primary-color) !important; - background: rgba(59, 130, 246, 0.1); -} - -/* Enhanced Form Elements */ -.form-control { - border: 2px solid var(--border-color); - border-radius: var(--border-radius-sm); - padding: 0.875rem 1rem; - font-size: 0.95rem; - background: var(--input-bg); - color: var(--text-primary); - transition: var(--transition); - box-shadow: none; -} - -.form-control:focus { - border-color: var(--primary-color); - box-shadow: var(--focus-ring); - background: var(--input-bg); - color: var(--text-primary); -} - -.form-control::placeholder { - color: var(--text-muted); - opacity: 0.8; -} - -.form-label { - font-weight: var(--font-weight-medium); - color: var(--text-primary); - margin-bottom: 0.5rem; -} - -.form-select { - border: 2px solid var(--border-color); - border-radius: var(--border-radius-sm); - padding: 0.875rem 1rem; - background: var(--input-bg); - color: var(--text-primary); - transition: var(--transition); -} - -.form-select:focus { - border-color: var(--primary-color); - box-shadow: var(--focus-ring); -} - -/* Enhanced Tables */ -.table { - border-radius: var(--border-radius); - overflow: hidden; - box-shadow: var(--card-shadow); - background: var(--card-bg); -} - -.table thead th { - background: var(--surface-variant); - border: none; - color: var(--text-primary); - font-weight: var(--font-weight-semibold); - padding: 1rem; - text-transform: uppercase; - font-size: 0.875rem; - letter-spacing: 0.05em; -} - -.table tbody tr { - border: none; - transition: var(--transition); -} - -.table tbody tr:hover { - background: var(--surface-variant); -} - -.table tbody td { - border: none; - padding: 1rem; - color: var(--text-primary); - border-bottom: 1px solid var(--border-light); -} - -.table tbody tr:last-child td { - border-bottom: none; -} - -/* Dashboard specific classes to replace inline styles */ -.timer-icon { - width: 48px; - height: 48px; -} - -.timer-status-icon { - width: 72px; - height: 72px; -} - -.timer-display { - font-family: 'Monaco', 'Consolas', monospace; - font-size: 1.25rem; - font-weight: 600; - color: var(--success-color); - background: var(--surface-variant); - padding: 1rem; - border-radius: var(--border-radius-sm); - text-align: center; -} - -.stats-icon { - width: 64px; - height: 64px; -} - -/* Force minimal rounded corners on all dropdowns */ -.dropdown-menu, -.btn-group .dropdown-menu, -.navbar .dropdown-menu, -.table .dropdown-menu, -.card .dropdown-menu { - border-radius: var(--border-radius-sm) !important; -} - -/* Also ensure form selects use minimal corners */ -.form-select, -.form-control { - border-radius: var(--border-radius-sm) !important; -} - -/* ===== ENHANCED COMMON PAGE STYLING PATTERNS ===== */ -/* Based on modern clients page design - Applied globally */ - -/* Modern Status Badge System */ -.status-badge { - padding: 6px 12px; - border-radius: var(--border-radius-full); - font-size: 12px; - font-weight: var(--font-weight-semibold); - letter-spacing: 0.5px; - display: inline-block; - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); - cursor: default; -} - -/* Enhanced Status Badge Large */ -.status-badge-large { - padding: 8px 16px; - border-radius: var(--border-radius-full); - font-size: 14px; - font-weight: var(--font-weight-semibold); - text-transform: uppercase; - letter-spacing: 0.5px; - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); - cursor: default; -} - -/* Modern Section Title */ -.section-title { - font-size: 16px; - font-weight: var(--font-weight-semibold); - border-bottom: 2px solid var(--primary-color); - padding-bottom: 8px; - position: relative; - color: var(--text-primary); - margin-bottom: 1rem; -} - -.section-title::after { - content: ''; - position: absolute; - bottom: -2px; - left: 0; - width: 30px; - height: 2px; - background: linear-gradient(90deg, var(--primary-color), transparent); -} - -/* Enhanced Detail Row System */ -.detail-row { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 12px; - padding: 8px 0; - border-bottom: 1px solid var(--border-light); - transition: var(--transition); -} - -.detail-row:hover { - background: var(--primary-50); - padding-left: 8px; - border-radius: var(--border-radius-sm); - border-bottom-color: var(--primary-200); -} - -.detail-label { - font-weight: var(--font-weight-semibold); - color: var(--text-secondary); - transition: color var(--transition); - font-size: 0.9rem; -} - -.detail-value { - font-weight: var(--font-weight-semibold); - color: var(--text-primary); - transition: color var(--transition); -} - -/* Enhanced Content Box */ -.content-box { - background: var(--surface-variant); - padding: 16px; - border-radius: var(--border-radius); - border-left: 4px solid var(--primary-color); - line-height: var(--line-height-relaxed); - position: relative; - overflow: hidden; - transition: var(--transition-slow); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); -} - -.content-box::before { - content: ''; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(59, 130, 246, 0.1), transparent); - transition: left 0.8s; -} - -.content-box:hover::before { - left: 100%; -} - -.content-box:hover { - transform: translateX(4px); - box-shadow: var(--card-shadow); - border-left-color: var(--primary-600); -} - -/* Enhanced Summary Card System */ -.summary-card { - border-radius: var(--border-radius-lg); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); - cursor: default; -} - -.summary-icon { - width: 48px; - height: 48px; - border-radius: var(--border-radius-sm); - display: inline-flex; - align-items: center; - justify-content: center; - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); -} - -.summary-label { - font-size: 12px; - color: var(--text-tertiary); - font-weight: var(--font-weight-semibold); - letter-spacing: 0.4px; - text-transform: uppercase; - margin-bottom: 4px; -} - -.summary-value { - font-size: 20px; - font-weight: var(--font-weight-extrabold); - color: var(--text-primary); - font-family: var(--font-family-mono); -} - -/* Enhanced Table Hover Effects */ -.table-hover tbody tr { - transition: var(--transition); -} - -.table-hover tbody tr:hover { - background-color: var(--primary-50); - transform: scale(1.002); - box-shadow: 0 2px 8px rgba(59, 130, 246, 0.1); -} - -/* Enhanced Button Group Animations */ -.btn-group .btn::before { - content: ''; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent); - transition: left 0.5s; - pointer-events: none; -} - -.btn-group .btn:hover::before { - left: 100%; -} - -/* Dark Theme Adaptations */ -[data-theme="dark"] .detail-row:hover { - background: var(--primary-900); - border-bottom-color: var(--primary-700); -} - -[data-theme="dark"] .content-box { - background: var(--surface-variant); - border-left-color: var(--primary-color); -} - -[data-theme="dark"] .content-box:hover { - background: var(--surface-hover); - border-left-color: var(--primary-400); -} - -[data-theme="dark"] .table-hover tbody tr:hover { - background-color: var(--primary-900); - box-shadow: 0 2px 8px rgba(96, 165, 250, 0.2); -} - -/* Mobile Responsive Enhancements */ -@media (max-width: 768px) { - .detail-row { - flex-direction: column; - align-items: flex-start; - gap: 4px; - padding: 12px 8px; - } - - .status-badge-large { - font-size: 12px; - padding: 6px 12px; - } - - .summary-card { - margin-bottom: 1rem; - } - - .content-box { - padding: 12px; - } - - .section-title { - font-size: 14px; - } -} - -@media (max-width: 576px) { - .summary-icon { - width: 36px; - height: 36px; - } - - .summary-value { - font-size: 18px; - } -} - -/* ===== TASK CARD SYSTEM ===== */ -/* Enhanced task cards for project and task views */ - -.task-card { - transition: var(--transition-slow); - border: 1px solid var(--border-color); - border-radius: var(--border-radius-lg); - overflow: hidden; - position: relative; - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); -} - -.task-card::before { - content: ''; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(59, 130, 246, 0.05), transparent); - transition: left 1.2s; - pointer-events: none; - z-index: 1; -} - -.task-card:hover::before { - left: 100%; -} - -.task-card:hover { - transform: translateY(-4px) scale(1.01); - box-shadow: var(--card-shadow-hover); - border-color: var(--primary-color); -} - -/* Priority-based left borders */ -.task-card.priority-low { - border-left: 4px solid var(--success-color); -} - -.task-card.priority-medium { - border-left: 4px solid var(--warning-color); -} - -.task-card.priority-high { - border-left: 4px solid #f97316; -} - -.task-card.priority-urgent { - border-left: 4px solid var(--danger-color); -} - -/* Enhanced Task Title Links */ -.task-title-link { - transition: var(--transition); - font-weight: var(--font-weight-semibold); - position: relative; - color: var(--text-primary); -} - -.task-title-link::after { - content: ''; - position: absolute; - bottom: -2px; - left: 0; - width: 0; - height: 2px; - background: var(--primary-color); - transition: width 0.3s ease; -} - -.task-title-link:hover::after { - width: 100%; -} - -.task-title-link:hover { - color: var(--primary-color) !important; - text-decoration: none !important; -} - -/* Enhanced Task Description */ -.task-description { - background: var(--bg-gradient-subtle); - border-radius: var(--border-radius); - padding: 12px; - border-left: 3px solid var(--primary-color); - position: relative; - overflow: hidden; - transition: var(--transition-slow); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); -} - -.task-description::before { - content: ''; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(59, 130, 246, 0.1), transparent); - transition: left 0.8s; -} - -.task-description:hover::before { - left: 100%; -} - -.task-description:hover { - transform: translateX(4px); - box-shadow: var(--card-shadow); - border-left-color: var(--primary-600); -} - -/* Task Meta Items */ -.task-meta-item { - transition: var(--transition); - padding: 4px 0; -} - -.task-meta-item:hover { - transform: translateX(4px); -} - -.task-meta-item .bg-opacity-10 { - transition: var(--transition); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); -} - -.task-meta-item:hover .bg-opacity-10 { - transform: scale(1.1); -} - -/* Enhanced Progress Bars */ -.progress { - background: var(--bg-gradient-subtle); - border-radius: var(--border-radius-sm); - overflow: hidden; - position: relative; - box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -} - -.progress::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 1px; - background: linear-gradient(90deg, transparent, var(--primary-color), transparent); -} - -.progress-bar { - background: linear-gradient(90deg, var(--primary-color) 0%, var(--primary-600) 100%); - border-radius: var(--border-radius-sm); - position: relative; - overflow: hidden; -} - -.progress-bar::before { - content: ''; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent); - animation: progress-shine 2s infinite; -} - -@keyframes progress-shine { - 0% { left: -100%; } - 100% { left: 100%; } -} - -/* Project Badge */ -.project-badge { - background: var(--surface-variant); - color: var(--text-secondary); - padding: 4px 8px; - border-radius: var(--border-radius-sm); - font-size: 12px; - font-weight: var(--font-weight-medium); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); - cursor: default; -} - -/* Priority Badge System */ -.priority-badge { - padding: 0.25rem 0.75rem; - border-radius: var(--border-radius-full); - font-size: 0.75rem; - font-weight: var(--font-weight-semibold); - text-transform: uppercase; - letter-spacing: 0.5px; - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); - cursor: default; -} - -/* Status Badge Variants */ -.status-todo { - background: linear-gradient(135deg, var(--gray-200) 0%, var(--gray-300) 100%); - color: var(--gray-600); - border: 1px solid var(--gray-400); -} - -.status-in_progress { - background: linear-gradient(135deg, var(--warning-light) 0%, #fde68a 100%); - color: #92400e; - border: 1px solid var(--warning-color); -} - -.status-review { - background: linear-gradient(135deg, var(--primary-100) 0%, var(--primary-200) 100%); - color: var(--primary-800); - border: 1px solid var(--primary-color); -} - -.status-done { - background: linear-gradient(135deg, var(--success-light) 0%, #bbf7d0 100%); - color: #166534; - border: 1px solid var(--success-color); -} - -.status-cancelled { - background: linear-gradient(135deg, var(--danger-light) 0%, #fecaca 100%); - color: #991b1b; - border: 1px solid var(--danger-color); -} - -/* Priority Badge Variants */ -.priority-low { - background: linear-gradient(135deg, var(--success-light) 0%, #bbf7d0 100%); - color: #166534; - border: 1px solid var(--success-color); -} - -.priority-medium { - background: linear-gradient(135deg, var(--warning-light) 0%, #fde68a 100%); - color: #92400e; - border: 1px solid var(--warning-color); -} - -.priority-high { - background: linear-gradient(135deg, #fed7aa 0%, #fdba74 100%); - color: #c2410c; - border: 1px solid #f97316; -} - -.priority-urgent { - background: linear-gradient(135deg, var(--danger-light) 0%, #fecaca 100%); - color: #991b1b; - border: 1px solid var(--danger-color); -} - -/* Dark Theme Task Adaptations */ -[data-theme="dark"] .task-card { - background: var(--card-bg); - border-color: var(--border-color); -} - -[data-theme="dark"] .task-card:hover { - border-color: var(--primary-color); - box-shadow: var(--card-shadow-hover); -} - -[data-theme="dark"] .task-description { - background: var(--bg-gradient-subtle); - border-left-color: var(--primary-color); -} - -[data-theme="dark"] .task-description:hover { - background: var(--surface-hover); -} - -[data-theme="dark"] .task-title-link { - color: var(--text-primary) !important; -} - -[data-theme="dark"] .task-title-link:hover { - color: var(--primary-color) !important; -} - -[data-theme="dark"] .progress { - background: var(--bg-gradient-subtle); -} - -[data-theme="dark"] .project-badge { - background: var(--surface-variant); - color: var(--text-secondary); -} - -/* Dark theme status badges */ -[data-theme="dark"] .status-todo { - background: linear-gradient(135deg, var(--gray-700) 0%, var(--gray-600) 100%); - color: var(--gray-300); - border-color: var(--gray-500); -} - -[data-theme="dark"] .status-in_progress { - background: linear-gradient(135deg, #451a03 0%, #78350f 100%); - color: var(--warning-color); - border-color: var(--warning-color); -} - -[data-theme="dark"] .status-review { - background: linear-gradient(135deg, #1e3a8a 0%, #1e40af 100%); - color: var(--primary-400); - border-color: var(--primary-color); -} - -[data-theme="dark"] .status-done { - background: linear-gradient(135deg, #14532d 0%, #166534 100%); - color: var(--success-color); - border-color: var(--success-color); -} - -[data-theme="dark"] .status-cancelled { - background: linear-gradient(135deg, #7f1d1d 0%, #991b1b 100%); - color: var(--danger-color); - border-color: var(--danger-color); -} - -[data-theme="dark"] .priority-low { - background: linear-gradient(135deg, #14532d 0%, #166534 100%); - color: var(--success-color); - border-color: var(--success-color); -} - -[data-theme="dark"] .priority-medium { - background: linear-gradient(135deg, #451a03 0%, #78350f 100%); - color: var(--warning-color); - border-color: var(--warning-color); -} - -[data-theme="dark"] .priority-high { - background: linear-gradient(135deg, #7c2d12 0%, #c2410c 100%); - color: #fb923c; - border-color: #f97316; -} - -[data-theme="dark"] .priority-urgent { - background: linear-gradient(135deg, #7f1d1d 0%, #991b1b 100%); - color: var(--danger-color); - border-color: var(--danger-color); -} - -/* ================================================== - DASHBOARD ENHANCEMENTS - Modern Styling - ================================================== */ - -/* Stagger animation for dashboard cards */ -.stagger-animation > * { - animation: cardSlideIn 0.5s cubic-bezier(0.16, 1, 0.3, 1) backwards; -} - -.stagger-animation > *:nth-child(1) { animation-delay: 0.05s; } -.stagger-animation > *:nth-child(2) { animation-delay: 0.1s; } -.stagger-animation > *:nth-child(3) { animation-delay: 0.15s; } -.stagger-animation > *:nth-child(4) { animation-delay: 0.2s; } -.stagger-animation > *:nth-child(5) { animation-delay: 0.25s; } -.stagger-animation > *:nth-child(6) { animation-delay: 0.3s; } - -@keyframes cardSlideIn { - from { - opacity: 0; - transform: translateY(30px) scale(0.95); - } - to { - opacity: 1; - transform: translateY(0) scale(1); - } -} - -/* Enhanced timer status icon */ -.timer-status-icon { - width: 80px; - height: 80px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); - transition: all var(--transition-slow); -} - -.timer-status-icon:hover { - transform: scale(1.05); - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15); -} - -/* Timer display styling */ -.timer-display { - font-size: 2.5rem; - font-weight: 800; - font-variant-numeric: tabular-nums; - letter-spacing: -0.02em; - color: var(--primary-color); - text-shadow: 0 2px 4px rgba(59, 130, 246, 0.1); -} - -/* Status badge */ -.status-badge { - display: inline-block; - padding: 0.375rem 0.875rem; - border-radius: var(--border-radius-full); - font-size: 0.875rem; - font-weight: 600; - letter-spacing: 0.025em; -} - -/* Enhanced statistics cards */ -.stat-card { - position: relative; - overflow: hidden; - cursor: default; -} - -.stat-card::after { - content: ''; - position: absolute; - top: 0; - right: 0; - width: 100px; - height: 100px; - background: radial-gradient(circle, rgba(59, 130, 246, 0.1) 0%, transparent 70%); - border-radius: 50%; - transform: translate(30%, -30%); -} - -/* Quick action cards with gradient effects */ -.quick-action-card { - position: relative; - transition: all var(--transition-slow); - cursor: pointer; -} - -.quick-action-card::before { - content: ''; - position: absolute; - inset: 0; - border-radius: inherit; - padding: 2px; - background: linear-gradient(135deg, var(--primary-color), var(--primary-600)); - -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); - mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); - -webkit-mask-composite: xor; - mask-composite: exclude; - opacity: 0; - transition: opacity var(--transition); -} - -.quick-action-card:hover::before { - opacity: 1; -} - -.quick-action-card:hover { - transform: translateY(-4px); -} - -/* Page header enhancements */ -.page-header { - margin-bottom: 2rem; - animation: slideInFromTop 0.5s cubic-bezier(0.16, 1, 0.3, 1); -} - -@keyframes slideInFromTop { - from { - opacity: 0; - transform: translateY(-20px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -/* Recent activity list enhancements */ -.activity-item { - padding: 1rem; - border-radius: var(--border-radius); - transition: all var(--transition); - border-left: 3px solid transparent; -} - -.activity-item:hover { - background: var(--surface-hover); - border-left-color: var(--primary-color); - transform: translateX(4px); -} - -/* Chart container enhancements */ -.chart-container { - position: relative; - padding: 1.5rem; - background: var(--surface-variant); - border-radius: var(--border-radius); - transition: all var(--transition); -} - -.chart-container:hover { - background: var(--surface-hover); - box-shadow: inset 0 0 0 1px var(--primary-color); -} - -/* Empty state enhancements */ -.empty-state { - text-align: center; - padding: 3rem 2rem; -} - -.empty-state-icon { - font-size: 3rem; - color: var(--text-muted); - margin-bottom: 1rem; - opacity: 0.5; -} - -.empty-state-title { - font-size: 1.25rem; - font-weight: 700; - color: var(--text-secondary); - margin-bottom: 0.5rem; -} - -.empty-state-text { - color: var(--text-tertiary); - margin-bottom: 1.5rem; -} - -/* Dark theme dashboard enhancements */ -[data-theme="dark"] .timer-display { - color: var(--primary-400); - text-shadow: 0 2px 8px rgba(96, 165, 250, 0.3); -} - -[data-theme="dark"] .stat-card::after { - background: radial-gradient(circle, rgba(96, 165, 250, 0.15) 0%, transparent 70%); -} - -[data-theme="dark"] .activity-item:hover { - background: var(--surface-variant); -} - -[data-theme="dark"] .chart-container { - background: var(--surface-variant); -} - -[data-theme="dark"] .chart-container:hover { - background: var(--surface-hover); -} - diff --git a/app/static/calendar.css b/app/static/calendar.css deleted file mode 100644 index 446cceb..0000000 --- a/app/static/calendar.css +++ /dev/null @@ -1,706 +0,0 @@ -/* ======================================== - TimeTracker Calendar Styles - ======================================== */ - -/* Calendar Container */ -#calendar { - min-height: 70vh; - background: var(--card-bg); - border-radius: var(--border-radius); - padding: 1rem; -} - -/* Calendar Header */ -.calendar-header { - display: flex; - align-items: center; - justify-content: space-between; - gap: 1rem; - flex-wrap: wrap; - margin-bottom: 1rem; -} - -.calendar-controls { - display: flex; - align-items: center; - gap: 0.5rem; - flex-wrap: wrap; -} - -.calendar-filters { - display: flex; - align-items: center; - gap: 0.5rem; - flex-wrap: wrap; -} - -.calendar-hours-summary { - display: flex; - align-items: center; - padding: 0.375rem 0.75rem; - background: var(--surface-variant); - border-radius: var(--border-radius); - border: 1px solid var(--border-color); -} - -.calendar-assign, -.calendar-filter-project, -.calendar-filter-task, -.calendar-filter-tags { - min-width: 200px; - max-width: 280px; -} - -/* FullCalendar Customization */ -.fc-toolbar-title { - font-weight: 600; - font-size: 1.5rem !important; - color: var(--text-primary); -} - -.fc-event { - cursor: pointer; - border-radius: 4px; - border-left-width: 4px !important; - font-size: 0.85rem; - padding: 2px 4px; - transition: var(--transition); -} - -.fc-event:hover { - opacity: 0.9; - transform: translateY(-1px); - box-shadow: var(--card-shadow-hover); -} - -.fc-event-time { - font-weight: 600; -} - -.fc-event-title { - font-weight: 400; -} - -/* Today button */ -.fc-today-button { - background-color: var(--primary-color) !important; - border-color: var(--primary-color) !important; -} - -.fc-today-button:hover { - background-color: var(--primary-dark) !important; -} - -/* Current time indicator */ -.fc-timegrid-now-indicator-line { - border-color: var(--danger-color); - border-width: 2px; -} - -.fc-timegrid-now-indicator-arrow { - border-color: var(--danger-color); -} - -/* Day cells */ -.fc-day-today { - background-color: var(--primary-50) !important; -} - -.fc-day-past { - background-color: var(--surface-variant); -} - -/* Time grid */ -.fc-timegrid-slot { - height: 3em; - border-color: var(--border-color); -} - -.fc-timegrid-slot-minor { - border-style: dotted; - border-color: var(--border-light); -} - -/* Header cells */ -.fc-col-header-cell { - padding: 0.75rem; - font-weight: 600; - background: var(--surface-variant); - color: var(--text-primary); - border-color: var(--border-color); -} - -.fc-col-header-cell-cushion { - padding: 0.5rem; - color: var(--text-primary); -} - -/* Calendar base styles */ -.fc { - color: var(--text-primary); -} - -.fc-theme-standard td, -.fc-theme-standard th { - border-color: var(--border-color); -} - -.fc-theme-standard .fc-scrollgrid { - border-color: var(--border-color); -} - -.fc .fc-daygrid-day-number { - color: var(--text-primary); -} - -.fc .fc-timegrid-slot-label { - color: var(--text-secondary); -} - -/* Event Modal Styles */ -.event-modal { - display: none; - position: fixed; - z-index: 10000; - left: 0; - top: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.5); - animation: fadeIn 0.2s ease; -} - -.event-modal.show { - display: flex; - align-items: center; - justify-content: center; -} - -.event-modal-content { - background-color: var(--card-bg); - color: var(--text-primary); - border-radius: var(--border-radius-lg); - box-shadow: var(--card-shadow-xl); - max-width: 600px; - width: 90%; - max-height: 90vh; - overflow-y: auto; - animation: slideUp 0.3s ease; -} - -.event-modal-header { - display: flex; - align-items: center; - justify-content: space-between; - padding: 1.5rem; - border-bottom: 1px solid var(--border-color); -} - -.event-modal-header h3 { - margin: 0; - font-size: 1.25rem; - font-weight: 600; - color: var(--text-primary); -} - -.event-modal-close { - background: none; - border: none; - font-size: 1.5rem; - cursor: pointer; - color: var(--text-muted); - padding: 0; - width: 32px; - height: 32px; - display: flex; - align-items: center; - justify-content: center; - border-radius: var(--border-radius-sm); - transition: var(--transition); -} - -.event-modal-close:hover { - background-color: var(--surface-hover); - color: var(--text-primary); -} - -.event-modal-body { - padding: 1.5rem; -} - -.event-modal-footer { - display: flex; - gap: 0.5rem; - justify-content: flex-end; - padding: 1rem 1.5rem; - border-top: 1px solid var(--border-color); - background-color: var(--surface-variant); - border-radius: 0 0 var(--border-radius-lg) var(--border-radius-lg); -} - -/* Event Detail View */ -.event-detail { - display: grid; - gap: 1rem; -} - -.event-detail-row { - display: grid; - grid-template-columns: 120px 1fr; - gap: 1rem; - align-items: start; -} - -.event-detail-label { - font-weight: 600; - color: var(--text-secondary); - font-size: 0.875rem; - padding-top: 0.5rem; -} - -.event-detail-value { - color: var(--text-primary); - padding: 0.5rem; - background: var(--surface-variant); - border-radius: var(--border-radius-sm); - min-height: 36px; -} - -.event-detail-badge { - display: inline-block; - padding: 0.25rem 0.75rem; - border-radius: var(--border-radius-full); - font-size: 0.75rem; - font-weight: 600; -} - -.event-detail-badge.billable { - background-color: var(--success-light); - color: var(--success-color); -} - -.event-detail-badge.non-billable { - background-color: var(--danger-light); - color: var(--danger-color); -} - -/* Recurring Events Modal */ -.recurring-list { - max-height: 400px; - overflow-y: auto; - margin-top: 1rem; -} - -.recurring-item { - padding: 1rem; - border: 1px solid var(--border-color); - border-radius: var(--border-radius); - margin-bottom: 0.75rem; - background: var(--card-bg); - cursor: default; -} - -.recurring-item-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 0.5rem; -} - -.recurring-item-title { - font-weight: 600; - color: var(--text-primary); - font-size: 1rem; -} - -.recurring-item-status { - display: inline-block; - padding: 0.25rem 0.5rem; - border-radius: var(--border-radius-xs); - font-size: 0.75rem; - font-weight: 600; -} - -.recurring-item-status.active { - background-color: var(--success-light); - color: var(--success-color); -} - -.recurring-item-status.inactive { - background-color: var(--surface-variant); - color: var(--text-muted); -} - -.recurring-item-details { - font-size: 0.875rem; - color: var(--text-secondary); - margin-bottom: 0.5rem; -} - -.recurring-item-actions { - display: flex; - gap: 0.5rem; - margin-top: 0.75rem; -} - -/* Daily Capacity Bar */ -.daily-capacity-bar { - margin: 1rem 0; - padding: 1rem; - background: var(--card-bg); - border: 1px solid var(--border-color); - border-radius: var(--border-radius); -} - -.capacity-bar-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 0.5rem; - font-size: 0.875rem; -} - -.capacity-bar-container { - height: 24px; - background: var(--surface-variant); - border-radius: var(--border-radius-full); - overflow: hidden; - position: relative; -} - -.capacity-bar-fill { - height: 100%; - transition: width 0.3s ease, background-color 0.3s ease; - border-radius: var(--border-radius-full); - position: relative; -} - -.capacity-bar-fill.capacity-ok { - background: linear-gradient(90deg, #10b981, #34d399); -} - -.capacity-bar-fill.capacity-warning { - background: linear-gradient(90deg, #f59e0b, #fbbf24); -} - -.capacity-bar-fill.capacity-over { - background: linear-gradient(90deg, #ef4444, #f87171); -} - -/* Legend */ -.calendar-legend { - display: flex; - gap: 1rem; - flex-wrap: wrap; - padding: 0.75rem; - background: var(--surface-variant); - border-radius: var(--border-radius); - margin-top: 1rem; -} - -.legend-item { - display: flex; - align-items: center; - gap: 0.5rem; - font-size: 0.875rem; - color: var(--text-secondary); -} - -.legend-color { - width: 16px; - height: 16px; - border-radius: 3px; -} - -/* Agenda View */ -.agenda-view { - display: none; -} - -.agenda-view.active { - display: block; -} - -.agenda-date-group { - margin-bottom: 2rem; -} - -.agenda-date-header { - font-weight: 600; - font-size: 1.125rem; - color: var(--text-primary); - padding-bottom: 0.75rem; - border-bottom: 2px solid var(--border-color); - margin-bottom: 1rem; -} - -.agenda-event { - display: flex; - gap: 1rem; - padding: 1rem; - border-left: 4px solid; - background: var(--card-bg); - border-radius: var(--border-radius); - margin-bottom: 0.75rem; - box-shadow: var(--card-shadow); - transition: var(--transition); - cursor: pointer; -} - -.agenda-event:hover { - transform: translateX(4px); - box-shadow: var(--card-shadow-hover); -} - -.agenda-event-time { - min-width: 100px; - font-weight: 600; - color: var(--text-secondary); -} - -.agenda-event-details { - flex: 1; -} - -.agenda-event-title { - font-weight: 600; - color: var(--text-primary); - margin-bottom: 0.25rem; -} - -.agenda-event-meta { - font-size: 0.875rem; - color: var(--text-secondary); -} - -/* Loading State */ -.calendar-loading { - display: none; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - z-index: 100; -} - -.calendar-loading.show { - display: block; -} - -.calendar-spinner { - border: 4px solid var(--border-color); - border-top: 4px solid var(--primary-color); - border-radius: 50%; - width: 48px; - height: 48px; - animation: spin 1s linear infinite; -} - -/* Keyboard Shortcuts Modal Styles */ -.shortcuts-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); - gap: 2rem; -} - -.shortcut-section { - display: flex; - flex-direction: column; - gap: 0.75rem; -} - -.shortcut-item { - display: flex; - align-items: center; - gap: 1rem; - padding: 0.5rem; - border-radius: var(--border-radius-sm); - transition: var(--transition); -} - -.shortcut-item:hover { - background: var(--surface-hover); -} - -.shortcut-item kbd { - display: inline-block; - padding: 0.25rem 0.5rem; - font-family: monospace; - font-size: 0.875rem; - font-weight: 600; - color: var(--text-primary); - background: var(--surface-variant); - border: 1px solid var(--border-color); - border-radius: var(--border-radius-sm); - box-shadow: 0 2px 0 rgba(0, 0, 0, 0.1); - min-width: 2rem; - text-align: center; -} - -.shortcut-item span { - flex: 1; - color: var(--text-secondary); -} - -/* Animations */ -@keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -@keyframes slideUp { - from { - transform: translateY(20px); - opacity: 0; - } - to { - transform: translateY(0); - opacity: 1; - } -} - -@keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} - -/* Responsive Design */ -@media (max-width: 768px) { - .calendar-header { - flex-direction: column; - align-items: stretch; - } - - .calendar-controls, - .calendar-filters { - flex-direction: column; - width: 100%; - } - - .calendar-assign, - .calendar-filter-project, - .calendar-filter-task, - .calendar-filter-tags { - width: 100%; - max-width: 100%; - } - - .event-modal-content { - width: 95%; - max-height: 95vh; - } - - .event-detail-row { - grid-template-columns: 1fr; - gap: 0.5rem; - } - - .event-detail-label { - padding-top: 0; - } - - .fc-toolbar { - flex-direction: column; - gap: 0.5rem; - } - - .fc-toolbar-chunk { - width: 100%; - text-align: center; - } -} - -/* Dark mode specific styles */ -[data-theme="dark"] #calendar { - background: var(--card-bg); -} - -[data-theme="dark"] .fc-col-header-cell { - background: var(--surface-variant); - color: var(--text-primary); -} - -[data-theme="dark"] .fc-day-today { - background-color: rgba(96, 165, 250, 0.1) !important; -} - -[data-theme="dark"] .event-modal-content { - background-color: var(--card-bg); - color: var(--text-primary); -} - -[data-theme="dark"] .event-modal-header { - border-bottom-color: var(--border-color); -} - -[data-theme="dark"] .event-modal-header h3 { - color: var(--text-primary); -} - -[data-theme="dark"] .event-modal-footer { - background-color: var(--surface-variant); - border-top-color: var(--border-color); -} - -[data-theme="dark"] .event-detail-value { - background: var(--surface-variant); - color: var(--text-primary); -} - -[data-theme="dark"] .recurring-item { - border-color: var(--border-color); - background: var(--card-bg); -} - -[data-theme="dark"] .calendar-legend { - background: var(--surface-variant); -} - -[data-theme="dark"] .agenda-event { - background: var(--card-bg); -} - -[data-theme="dark"] .agenda-date-header, -[data-theme="dark"] .agenda-event-title { - color: var(--text-primary); -} - -[data-theme="dark"] .fc .fc-button-primary { - background-color: var(--primary-color); - border-color: var(--primary-color); -} - -[data-theme="dark"] .fc .fc-button-primary:hover { - background-color: var(--primary-dark); - border-color: var(--primary-dark); -} - -[data-theme="dark"] .fc .fc-button-primary:disabled { - background-color: var(--text-muted); - border-color: var(--text-muted); -} - -/* Print styles */ -@media print { - .calendar-header, - .calendar-controls, - .event-modal { - display: none !important; - } - - #calendar { - min-height: auto; - } - - .fc-event { - break-inside: avoid; - } -} diff --git a/app/static/commands.js b/app/static/commands.js index f8aef62..062e37f 100644 --- a/app/static/commands.js +++ b/app/static/commands.js @@ -12,32 +12,25 @@ function $all(sel, root){ return Array.from((root||document).querySelectorAll(sel)); } function openModal(){ - try { - const el = $('#commandPaletteModal'); - if (!el) return; - const modal = bootstrap.Modal.getOrCreateInstance(el, { backdrop: 'static' }); - modal.show(); - // Focus input after show animation - setTimeout(() => $('#commandPaletteInput')?.focus(), 150); - refreshCommands(); - renderList(); - } catch(e) {} + const el = $('#commandPaletteModal'); + if (!el) return; + el.classList.remove('hidden'); + setTimeout(() => $('#commandPaletteInput')?.focus(), 50); + refreshCommands(); + renderList(); } function closeModal(){ - try { - const el = $('#commandPaletteModal'); - if (!el) return; - const modal = bootstrap.Modal.getOrCreateInstance(el); - modal.hide(); - clearFilter(); - } catch(e) {} + const el = $('#commandPaletteModal'); + if (!el) return; + el.classList.add('hidden'); + clearFilter(); } // Timer helpers async function getActiveTimer(){ try { - const res = await fetch('/api/timer/status'); + const res = await fetch('/timer/status', { credentials: 'same-origin' }); if (!res.ok) return null; const json = await res.json(); return json && json.active ? json.timer : null; @@ -53,7 +46,8 @@ try { const active = await getActiveTimer(); if (!active) { showToast('No active timer', 'warning'); return; } - const res = await fetch('/api/timer/stop', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}) }); + const token = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || ''; + const res = await fetch('/timer/stop', { method: 'POST', headers: { 'X-CSRF-Token': token }, credentials: 'same-origin' }); if (res.ok) { showToast('Timer stopped', 'info'); } else { @@ -118,12 +112,14 @@ const list = $('#commandPaletteList'); if (!list) return; list.innerHTML = ''; + // Ensure container has modern styling + list.className = 'flex flex-col max-h-96 overflow-y-auto divide-y divide-border-light dark:divide-border-dark'; filtered.forEach((cmd, idx) => { const li = document.createElement('button'); li.type = 'button'; - li.className = 'list-group-item list-group-item-action d-flex justify-content-between align-items-center'; + li.className = 'px-3 py-2 text-left flex justify-between items-center hover:bg-background-light dark:hover:bg-background-dark focus:outline-none focus:ring-2 focus:ring-primary'; li.setAttribute('data-idx', String(idx)); - li.innerHTML = `${cmd.title}${cmd.hint ? `${cmd.hint}` : ''}`; + li.innerHTML = `${cmd.title}${cmd.hint ? `${cmd.hint}` : ''}`; li.addEventListener('click', () => { closeModal(); setTimeout(() => cmd.action(), 50); }); list.appendChild(li); }); @@ -131,8 +127,10 @@ } function highlightSelected(){ - $all('#commandPaletteList .list-group-item').forEach((el, idx) => { - el.classList.toggle('active', idx === selectedIdx); + $all('#commandPaletteList > button').forEach((el, idx) => { + const isActive = idx === selectedIdx; + el.classList.toggle('bg-background-light', isActive); + el.classList.toggle('dark:bg-background-dark', isActive); }); } @@ -185,7 +183,8 @@ // Modal-specific keyboard handling document.addEventListener('keydown', (ev) => { - if (!$('#commandPaletteModal')?.classList.contains('show')) return; + const modal = $('#commandPaletteModal'); + if (!modal || modal.classList.contains('hidden')) return; if (ev.key === 'Escape'){ ev.preventDefault(); closeModal(); return; } if (ev.key === 'ArrowDown'){ ev.preventDefault(); selectedIdx = Math.min(selectedIdx + 1, filtered.length - 1); highlightSelected(); return; } if (ev.key === 'ArrowUp'){ ev.preventDefault(); selectedIdx = Math.max(selectedIdx - 1, 0); highlightSelected(); return; } diff --git a/app/static/empty-states.css b/app/static/empty-states.css deleted file mode 100644 index 36f6a3b..0000000 --- a/app/static/empty-states.css +++ /dev/null @@ -1,478 +0,0 @@ -/* ========================================================================== - Enhanced Empty States - Beautiful empty state designs with illustrations and animations - ========================================================================== */ - -/* Empty State Container */ -.empty-state { - text-align: center; - padding: 4rem 2rem; - max-width: 500px; - margin: 0 auto; - animation: fade-in-up 0.5s ease; -} - -.empty-state-sm { - padding: 2rem 1rem; -} - -.empty-state-lg { - padding: 6rem 2rem; -} - -/* Empty State Icon */ -.empty-state-icon { - width: 120px; - height: 120px; - margin: 0 auto 2rem; - position: relative; -} - -.empty-state-icon-sm { - width: 80px; - height: 80px; - margin-bottom: 1.5rem; -} - -.empty-state-icon-lg { - width: 160px; - height: 160px; - margin-bottom: 2.5rem; -} - -/* Animated Icon Container */ -.empty-state-icon-animated { - animation: float 3s ease-in-out infinite; -} - -@keyframes float { - 0%, 100% { - transform: translateY(0); - } - 50% { - transform: translateY(-10px); - } -} - -/* Icon Background Circle */ -.empty-state-icon-circle { - width: 100%; - height: 100%; - border-radius: 50%; - background: linear-gradient(135deg, var(--primary-100), var(--primary-50)); - display: flex; - align-items: center; - justify-content: center; - position: relative; - box-shadow: 0 10px 30px rgba(59, 130, 246, 0.15); -} - -[data-theme="dark"] .empty-state-icon-circle { - background: linear-gradient(135deg, var(--primary-900), var(--primary-800)); -} - -/* Pulsing Ring */ -.empty-state-icon-circle::before { - content: ''; - position: absolute; - top: -10px; - left: -10px; - right: -10px; - bottom: -10px; - border-radius: 50%; - border: 2px solid var(--primary-200); - animation: pulse-ring 2s ease-out infinite; - opacity: 0.5; -} - -[data-theme="dark"] .empty-state-icon-circle::before { - border-color: var(--primary-700); -} - -@keyframes pulse-ring { - 0% { - transform: scale(0.95); - opacity: 1; - } - 100% { - transform: scale(1.1); - opacity: 0; - } -} - -/* Icon */ -.empty-state-icon i { - font-size: 3rem; - color: var(--primary-500); - animation: fade-in-scale 0.6s ease; -} - -@keyframes fade-in-scale { - from { - opacity: 0; - transform: scale(0.5); - } - to { - opacity: 1; - transform: scale(1); - } -} - -/* SVG Illustration */ -.empty-state-illustration { - width: 100%; - max-width: 300px; - margin: 0 auto 2rem; - opacity: 0.9; -} - -/* Title */ -.empty-state-title { - font-size: 1.5rem; - font-weight: 600; - color: var(--text-primary); - margin-bottom: 0.75rem; - line-height: 1.3; -} - -.empty-state-title-sm { - font-size: 1.25rem; -} - -.empty-state-title-lg { - font-size: 1.75rem; -} - -/* Description */ -.empty-state-description { - font-size: 1rem; - color: var(--text-secondary); - margin-bottom: 2rem; - line-height: 1.6; -} - -.empty-state-description-muted { - color: var(--text-muted); - font-size: 0.9rem; -} - -/* Actions */ -.empty-state-actions { - display: flex; - gap: 1rem; - justify-content: center; - flex-wrap: wrap; -} - -.empty-state-actions .btn { - min-width: 140px; -} - -/* Specific Empty States */ - -/* No Data */ -.empty-state-no-data .empty-state-icon-circle { - background: linear-gradient(135deg, var(--gray-100), var(--gray-50)); -} - -[data-theme="dark"] .empty-state-no-data .empty-state-icon-circle { - background: linear-gradient(135deg, var(--gray-800), var(--gray-900)); -} - -.empty-state-no-data i { - color: var(--gray-500); -} - -/* No Results */ -.empty-state-no-results .empty-state-icon-circle { - background: linear-gradient(135deg, var(--warning-light), var(--warning-50)); -} - -[data-theme="dark"] .empty-state-no-results .empty-state-icon-circle { - background: linear-gradient(135deg, var(--warning-900), var(--warning-800)); -} - -.empty-state-no-results i { - color: var(--warning-color); -} - -/* Error */ -.empty-state-error .empty-state-icon-circle { - background: linear-gradient(135deg, var(--danger-light), var(--danger-50)); -} - -[data-theme="dark"] .empty-state-error .empty-state-icon-circle { - background: linear-gradient(135deg, var(--danger-900), var(--danger-800)); -} - -.empty-state-error i { - color: var(--danger-color); -} - -/* Success */ -.empty-state-success .empty-state-icon-circle { - background: linear-gradient(135deg, var(--success-light), var(--success-50)); -} - -[data-theme="dark"] .empty-state-success .empty-state-icon-circle { - background: linear-gradient(135deg, var(--success-900), var(--success-800)); -} - -.empty-state-success i { - color: var(--success-color); -} - -/* Info */ -.empty-state-info .empty-state-icon-circle { - background: linear-gradient(135deg, var(--info-light), var(--info-50)); -} - -[data-theme="dark"] .empty-state-info .empty-state-icon-circle { - background: linear-gradient(135deg, var(--info-900), var(--info-800)); -} - -.empty-state-info i { - color: var(--info-color); -} - -/* Features List */ -.empty-state-features { - text-align: left; - max-width: 400px; - margin: 2rem auto 2rem; -} - -.empty-state-feature { - display: flex; - align-items: flex-start; - gap: 1rem; - padding: 0.75rem; - margin-bottom: 0.5rem; - background: var(--surface-variant); - border-radius: var(--border-radius-sm); - cursor: default; -} - -.empty-state-feature-icon { - width: 24px; - height: 24px; - flex-shrink: 0; - color: var(--primary-color); -} - -.empty-state-feature-content { - flex: 1; -} - -.empty-state-feature-title { - font-weight: 600; - color: var(--text-primary); - margin-bottom: 0.25rem; - font-size: 0.95rem; -} - -.empty-state-feature-description { - font-size: 0.85rem; - color: var(--text-secondary); - line-height: 1.4; -} - -/* Quick Tips */ -.empty-state-tips { - background: var(--info-50); - border: 1px solid var(--info-200); - border-radius: var(--border-radius); - padding: 1.5rem; - margin-top: 2rem; - text-align: left; -} - -[data-theme="dark"] .empty-state-tips { - background: var(--info-900); - border-color: var(--info-700); -} - -.empty-state-tips-title { - display: flex; - align-items: center; - gap: 0.5rem; - font-weight: 600; - color: var(--info-color); - margin-bottom: 1rem; -} - -.empty-state-tips-list { - list-style: none; - padding: 0; - margin: 0; -} - -.empty-state-tips-list li { - padding: 0.5rem 0; - padding-left: 1.5rem; - position: relative; - color: var(--text-secondary); - font-size: 0.9rem; -} - -.empty-state-tips-list li::before { - content: '✓'; - position: absolute; - left: 0; - color: var(--info-color); - font-weight: bold; -} - -/* Animated Illustrations */ -.empty-state-animated-bg { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 200%; - height: 200%; - opacity: 0.05; - pointer-events: none; -} - -.empty-state-animated-bg::before, -.empty-state-animated-bg::after { - content: ''; - position: absolute; - border-radius: 50%; - background: var(--primary-color); -} - -.empty-state-animated-bg::before { - width: 300px; - height: 300px; - top: 20%; - left: 10%; - animation: float-slow 10s ease-in-out infinite; -} - -.empty-state-animated-bg::after { - width: 200px; - height: 200px; - bottom: 20%; - right: 10%; - animation: float-slow 8s ease-in-out infinite reverse; -} - -@keyframes float-slow { - 0%, 100% { - transform: translate(0, 0); - } - 50% { - transform: translate(30px, -30px); - } -} - -/* Compact Empty State */ -.empty-state-compact { - padding: 2rem 1rem; - background: var(--surface-variant); - border-radius: var(--border-radius); - border: 2px dashed var(--border-color); -} - -.empty-state-compact .empty-state-icon { - width: 60px; - height: 60px; - margin-bottom: 1rem; -} - -.empty-state-compact .empty-state-title { - font-size: 1.1rem; - margin-bottom: 0.5rem; -} - -.empty-state-compact .empty-state-description { - font-size: 0.9rem; - margin-bottom: 1rem; -} - -/* Inline Empty State */ -.empty-state-inline { - display: flex; - align-items: center; - gap: 1.5rem; - padding: 1.5rem; - text-align: left; -} - -.empty-state-inline .empty-state-icon { - margin: 0; - width: 80px; - height: 80px; -} - -.empty-state-inline .empty-state-content { - flex: 1; -} - -.empty-state-inline .empty-state-title { - margin-bottom: 0.5rem; -} - -.empty-state-inline .empty-state-description { - margin-bottom: 1rem; -} - -/* Card Empty State */ -.empty-state-card { - background: var(--card-bg); - border-radius: var(--border-radius); - box-shadow: var(--card-shadow); - padding: 3rem 2rem; -} - -/* Responsive */ -@media (max-width: 768px) { - .empty-state { - padding: 3rem 1rem; - } - - .empty-state-icon { - width: 100px; - height: 100px; - } - - .empty-state-title { - font-size: 1.25rem; - } - - .empty-state-description { - font-size: 0.95rem; - } - - .empty-state-actions { - flex-direction: column; - } - - .empty-state-actions .btn { - width: 100%; - min-width: 0; - } - - .empty-state-inline { - flex-direction: column; - text-align: center; - } - - .empty-state-inline .empty-state-content { - text-align: center; - } -} - -/* Print Styles */ -@media print { - .empty-state { - page-break-inside: avoid; - } - - .empty-state-icon-circle::before { - display: none; - } -} - diff --git a/app/static/enhanced-search.css b/app/static/enhanced-search.css deleted file mode 100644 index c81ac8f..0000000 --- a/app/static/enhanced-search.css +++ /dev/null @@ -1,483 +0,0 @@ -/* ========================================================================== - Enhanced Search System - Instant search, autocomplete, and advanced filtering - ========================================================================== */ - -/* Search Container */ -.search-enhanced { - position: relative; - width: 100%; - max-width: 600px; -} - -.search-input-wrapper { - position: relative; - display: flex; - align-items: center; - background: var(--card-bg); - border: 2px solid var(--border-color); - border-radius: var(--border-radius); - padding: 0.5rem 1rem; - transition: var(--transition); - box-shadow: var(--card-shadow); -} - -.search-input-wrapper:focus-within { - border-color: var(--primary-color); - box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1), var(--card-shadow-hover); -} - -.search-input-wrapper .search-icon { - color: var(--text-muted); - margin-right: 0.75rem; - font-size: 1.1rem; -} - -.search-input-wrapper.searching .search-icon { - animation: search-pulse 1.5s ease-in-out infinite; -} - -@keyframes search-pulse { - 0%, 100% { - opacity: 1; - transform: scale(1); - } - 50% { - opacity: 0.5; - transform: scale(1.1); - } -} - -.search-enhanced input { - flex: 1; - border: none; - outline: none; - background: transparent; - font-size: 1rem; - color: var(--text-primary); - padding: 0.25rem 0; -} - -.search-enhanced input::placeholder { - color: var(--text-muted); -} - -/* Search Actions */ -.search-actions { - display: flex; - gap: 0.5rem; - align-items: center; -} - -.search-clear-btn { - background: none; - border: none; - color: var(--text-muted); - cursor: pointer; - padding: 0.25rem; - border-radius: 50%; - transition: var(--transition); - display: flex; - align-items: center; - justify-content: center; - width: 24px; - height: 24px; -} - -.search-clear-btn:hover { - background: var(--surface-hover); - color: var(--text-primary); -} - -.search-kbd { - display: inline-flex; - align-items: center; - justify-content: center; - min-width: 24px; - height: 24px; - padding: 0 0.5rem; - font-size: 0.75rem; - font-family: var(--font-family-mono); - color: var(--text-secondary); - background: var(--surface-variant); - border: 1px solid var(--border-color); - border-radius: 4px; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); -} - -/* Autocomplete Dropdown */ -.search-autocomplete { - position: absolute; - top: calc(100% + 0.5rem); - left: 0; - right: 0; - background: var(--card-bg); - border: 1px solid var(--border-color); - border-radius: var(--border-radius); - box-shadow: var(--card-shadow-lg); - max-height: 400px; - overflow-y: auto; - z-index: var(--z-dropdown); - opacity: 0; - transform: translateY(-10px); - pointer-events: none; - transition: opacity 0.2s ease, transform 0.2s ease; -} - -.search-autocomplete.show { - opacity: 1; - transform: translateY(0); - pointer-events: auto; -} - -/* Autocomplete Sections */ -.search-section { - padding: 0.75rem 0; - border-bottom: 1px solid var(--border-light); -} - -.search-section:last-child { - border-bottom: none; -} - -.search-section-title { - padding: 0.5rem 1rem; - font-size: 0.75rem; - font-weight: 600; - text-transform: uppercase; - color: var(--text-muted); - letter-spacing: 0.5px; -} - -/* Autocomplete Items */ -.search-item { - display: flex; - align-items: center; - padding: 0.75rem 1rem; - cursor: pointer; - transition: var(--transition); - color: var(--text-primary); - text-decoration: none; -} - -.search-item:hover, -.search-item.active { - background: var(--surface-hover); - color: var(--primary-color); -} - -.search-item-icon { - width: 32px; - height: 32px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 6px; - background: var(--surface-variant); - margin-right: 0.75rem; - flex-shrink: 0; -} - -.search-item:hover .search-item-icon { - background: var(--primary-100); - color: var(--primary-color); -} - -.search-item-content { - flex: 1; - min-width: 0; -} - -.search-item-title { - font-weight: 500; - margin-bottom: 0.25rem; - display: flex; - align-items: center; - gap: 0.5rem; -} - -.search-item-title mark { - background: var(--warning-light); - color: var(--text-primary); - padding: 0 2px; - border-radius: 2px; -} - -[data-theme="dark"] .search-item-title mark { - background: var(--warning-900); - color: var(--warning-color); -} - -.search-item-description { - font-size: 0.875rem; - color: var(--text-secondary); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.search-item-meta { - display: flex; - align-items: center; - gap: 0.5rem; - margin-left: auto; - padding-left: 1rem; - flex-shrink: 0; -} - -.search-item-badge { - font-size: 0.75rem; - padding: 0.25rem 0.5rem; - border-radius: var(--border-radius-xs); - background: var(--surface-variant); - color: var(--text-secondary); - font-weight: 500; -} - -/* Recent Searches */ -.search-recent { - padding: 0.75rem 1rem; -} - -.search-recent-item { - display: flex; - align-items: center; - padding: 0.5rem; - margin-bottom: 0.25rem; - border-radius: var(--border-radius-sm); - cursor: pointer; - transition: var(--transition); - color: var(--text-secondary); -} - -.search-recent-item:hover { - background: var(--surface-hover); - color: var(--text-primary); -} - -.search-recent-item i { - margin-right: 0.75rem; - opacity: 0.5; -} - -.search-recent-clear { - padding: 0.5rem 1rem; - text-align: center; -} - -.search-recent-clear button { - background: none; - border: none; - color: var(--text-muted); - cursor: pointer; - font-size: 0.875rem; - padding: 0.5rem 1rem; - border-radius: var(--border-radius-sm); - transition: var(--transition); -} - -.search-recent-clear button:hover { - background: var(--surface-hover); - color: var(--text-primary); -} - -/* No Results */ -.search-no-results { - padding: 2rem; - text-align: center; - color: var(--text-muted); -} - -.search-no-results i { - font-size: 2rem; - margin-bottom: 1rem; - opacity: 0.5; -} - -.search-no-results p { - margin: 0; -} - -/* Search Filters */ -.search-filters { - display: flex; - gap: 0.5rem; - padding: 0.75rem 1rem; - border-bottom: 1px solid var(--border-light); - flex-wrap: wrap; -} - -.search-filter-chip { - display: inline-flex; - align-items: center; - gap: 0.5rem; - padding: 0.375rem 0.75rem; - background: var(--surface-variant); - border: 1px solid var(--border-color); - border-radius: var(--border-radius-full); - font-size: 0.875rem; - color: var(--text-secondary); - cursor: pointer; - transition: var(--transition); -} - -.search-filter-chip:hover, -.search-filter-chip.active { - background: var(--primary-color); - color: white; - border-color: var(--primary-color); -} - -.search-filter-chip i { - font-size: 0.75rem; -} - -/* Search Stats */ -.search-stats { - padding: 0.75rem 1rem; - font-size: 0.875rem; - color: var(--text-muted); - background: var(--surface-variant); - border-bottom: 1px solid var(--border-light); -} - -.search-stats strong { - color: var(--text-primary); - font-weight: 600; -} - -/* Loading State */ -.search-loading { - padding: 2rem; - text-align: center; -} - -.search-loading .loading-spinner { - margin: 0 auto 1rem; -} - -/* Keyboard Navigation Indicator */ -.search-item.keyboard-focus { - background: var(--surface-hover); - outline: 2px solid var(--primary-color); - outline-offset: -2px; -} - -/* Search Suggestions */ -.search-suggestions { - padding: 0.75rem 1rem; -} - -.search-suggestion-item { - display: flex; - align-items: center; - padding: 0.5rem; - border-radius: var(--border-radius-sm); - cursor: pointer; - transition: var(--transition); - color: var(--text-secondary); - font-size: 0.875rem; -} - -.search-suggestion-item:hover { - background: var(--surface-hover); - color: var(--text-primary); -} - -.search-suggestion-item i { - margin-right: 0.75rem; - font-size: 0.75rem; - opacity: 0.5; -} - -/* Advanced Search Toggle */ -.search-advanced-toggle { - padding: 0.75rem 1rem; - text-align: center; - border-top: 1px solid var(--border-light); -} - -.search-advanced-toggle button { - background: none; - border: none; - color: var(--primary-color); - cursor: pointer; - font-size: 0.875rem; - font-weight: 500; - padding: 0.5rem 1rem; - border-radius: var(--border-radius-sm); - transition: var(--transition); -} - -.search-advanced-toggle button:hover { - background: var(--primary-50); -} - -[data-theme="dark"] .search-advanced-toggle button:hover { - background: var(--primary-900); -} - -/* Mobile Responsive */ -@media (max-width: 768px) { - .search-enhanced { - max-width: 100%; - } - - .search-autocomplete { - max-height: 70vh; - } - - .search-item-meta { - display: none; - } - - .search-kbd { - display: none; - } -} - -/* Scrollbar Styling */ -.search-autocomplete::-webkit-scrollbar { - width: 8px; -} - -.search-autocomplete::-webkit-scrollbar-track { - background: var(--surface-variant); - border-radius: 4px; -} - -.search-autocomplete::-webkit-scrollbar-thumb { - background: var(--border-color); - border-radius: 4px; -} - -.search-autocomplete::-webkit-scrollbar-thumb:hover { - background: var(--text-muted); -} - -/* Animation for dropdown appearance */ -@keyframes search-dropdown-in { - from { - opacity: 0; - transform: translateY(-10px) scale(0.95); - } - to { - opacity: 1; - transform: translateY(0) scale(1); - } -} - -.search-autocomplete.show { - animation: search-dropdown-in 0.2s ease; -} - -/* Highlight active search */ -.search-input-wrapper.has-value { - border-color: var(--primary-color); - background: var(--primary-50); -} - -[data-theme="dark"] .search-input-wrapper.has-value { - background: var(--primary-900); -} - diff --git a/app/static/enhanced-search.js b/app/static/enhanced-search.js index 5d45651..1921114 100644 --- a/app/static/enhanced-search.js +++ b/app/static/enhanced-search.js @@ -34,6 +34,16 @@ init() { this.createSearchUI(); this.bindEvents(); + // Proactively disable native autofill/auto-complete behaviors + try { + this.input.setAttribute('autocomplete', 'off'); + this.input.setAttribute('autocapitalize', 'off'); + this.input.setAttribute('autocorrect', 'off'); + this.input.setAttribute('spellcheck', 'false'); + // Trick some Chromium versions + this.input.setAttribute('name', 'q_search'); + this.input.setAttribute('data-lpignore', 'true'); + } catch(e) {} } createSearchUI() { @@ -46,7 +56,7 @@ const inputWrapper = document.createElement('div'); inputWrapper.className = 'search-input-wrapper'; inputWrapper.innerHTML = ` - + `; // Move input into wrapper @@ -57,8 +67,8 @@ const actions = document.createElement('div'); actions.className = 'search-actions'; actions.innerHTML = ` - Ctrl+K `; diff --git a/app/static/enhanced-tables.css b/app/static/enhanced-tables.css deleted file mode 100644 index 952e4b2..0000000 --- a/app/static/enhanced-tables.css +++ /dev/null @@ -1,552 +0,0 @@ -/* ========================================================================== - Enhanced Data Tables - Advanced table features: sorting, filtering, inline editing, sticky headers - ========================================================================== */ - -/* Enhanced Table Container */ -.table-enhanced-wrapper { - position: relative; - background: var(--card-bg); - border-radius: var(--border-radius); - box-shadow: var(--card-shadow); - overflow: hidden; -} - -/* Table Toolbar */ -.table-toolbar { - display: flex; - align-items: center; - justify-content: space-between; - padding: 1rem 1.25rem; - border-bottom: 1px solid var(--border-color); - background: var(--surface-variant); - flex-wrap: wrap; - gap: 1rem; -} - -.table-toolbar-left, -.table-toolbar-right { - display: flex; - align-items: center; - gap: 0.75rem; -} - -.table-search-box { - position: relative; - width: 250px; -} - -.table-search-box input { - width: 100%; - padding: 0.5rem 0.75rem 0.5rem 2.5rem; - border: 1px solid var(--border-color); - border-radius: var(--border-radius-sm); - background: var(--card-bg); - font-size: 0.9rem; - transition: var(--transition); -} - -.table-search-box input:focus { - outline: none; - border-color: var(--primary-color); - box-shadow: var(--focus-ring); -} - -.table-search-box i { - position: absolute; - left: 0.75rem; - top: 50%; - transform: translateY(-50%); - color: var(--text-muted); -} - -.table-filter-btn, -.table-columns-btn, -.table-export-btn { - padding: 0.5rem 1rem; - border: 1px solid var(--border-color); - background: var(--card-bg); - border-radius: var(--border-radius-sm); - color: var(--text-secondary); - cursor: pointer; - transition: var(--transition); - font-size: 0.9rem; - display: flex; - align-items: center; - gap: 0.5rem; -} - -.table-filter-btn:hover, -.table-columns-btn:hover, -.table-export-btn:hover { - background: var(--surface-hover); - border-color: var(--primary-color); - color: var(--primary-color); -} - -.table-filter-btn.active { - background: var(--primary-color); - border-color: var(--primary-color); - color: white; -} - -/* Enhanced Table */ -.table-enhanced { - width: 100%; - border-collapse: separate; - border-spacing: 0; - font-size: 0.9rem; -} - -/* Sticky Header */ -.table-enhanced-sticky thead th { - position: sticky; - top: 0; - z-index: 10; - background: var(--surface-variant); - box-shadow: 0 1px 0 var(--border-color); -} - -/* Table Header */ -.table-enhanced thead th { - padding: 0.875rem 1rem; - font-weight: 600; - text-align: left; - color: var(--text-secondary); - background: var(--surface-variant); - border-bottom: 2px solid var(--border-color); - white-space: nowrap; - user-select: none; -} - -/* Sortable Columns */ -.table-enhanced thead th.sortable { - cursor: pointer; - transition: var(--transition); -} - -.table-enhanced thead th.sortable:hover { - background: var(--surface-hover); - color: var(--primary-color); -} - -.table-enhanced thead th.sortable::after { - content: '\f0dc'; - font-family: 'Font Awesome 6 Free'; - font-weight: 900; - margin-left: 0.5rem; - opacity: 0.3; - transition: var(--transition); -} - -.table-enhanced thead th.sortable.sort-asc::after { - content: '\f0de'; - opacity: 1; - color: var(--primary-color); -} - -.table-enhanced thead th.sortable.sort-desc::after { - content: '\f0dd'; - opacity: 1; - color: var(--primary-color); -} - -/* Resizable Columns */ -.table-enhanced thead th.resizable { - position: relative; -} - -.column-resizer { - position: absolute; - right: 0; - top: 0; - bottom: 0; - width: 4px; - cursor: col-resize; - user-select: none; - background: transparent; - transition: background 0.2s; -} - -.column-resizer:hover, -.column-resizer.resizing { - background: var(--primary-color); -} - -/* Table Body */ -.table-enhanced tbody td { - padding: 0.875rem 1rem; - border-bottom: 1px solid var(--border-light); - color: var(--text-primary); -} - -.table-enhanced tbody tr { - transition: var(--transition); -} - -.table-enhanced tbody tr:hover { - background: var(--surface-hover); -} - -.table-enhanced tbody tr.selected { - background: var(--primary-50); -} - -[data-theme="dark"] .table-enhanced tbody tr.selected { - background: var(--primary-900); -} - -/* Editable Cells */ -.table-cell-editable { - cursor: pointer; - position: relative; -} - -.table-cell-editable:hover { - background: var(--surface-hover); - outline: 1px dashed var(--border-color); -} - -.table-cell-editing { - padding: 0 !important; -} - -.table-cell-editing input, -.table-cell-editing select, -.table-cell-editing textarea { - width: 100%; - border: 2px solid var(--primary-color); - padding: 0.875rem 1rem; - background: var(--card-bg); - font-size: 0.9rem; - outline: none; -} - -.table-cell-editing textarea { - min-height: 80px; - resize: vertical; -} - -/* Cell Actions */ -.table-cell-actions { - opacity: 0; - transition: opacity 0.2s; -} - -.table-enhanced tbody tr:hover .table-cell-actions { - opacity: 1; -} - -/* Checkbox Column */ -.table-checkbox-cell { - width: 40px; - text-align: center; -} - -.table-checkbox { - width: 18px; - height: 18px; - cursor: pointer; -} - -/* Action Buttons in Cells */ -.table-action-btn { - padding: 0.375rem 0.75rem; - border: none; - background: transparent; - color: var(--text-secondary); - cursor: pointer; - border-radius: var(--border-radius-xs); - transition: var(--transition); - font-size: 0.9rem; -} - -.table-action-btn:hover { - background: var(--surface-hover); - color: var(--primary-color); -} - -.table-action-btn.btn-danger:hover { - background: var(--danger-light); - color: var(--danger-color); -} - -/* Loading State */ -.table-loading { - position: relative; - pointer-events: none; - opacity: 0.6; -} - -.table-loading-overlay { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(255, 255, 255, 0.8); - display: flex; - align-items: center; - justify-content: center; - z-index: 20; -} - -[data-theme="dark"] .table-loading-overlay { - background: rgba(15, 23, 42, 0.8); -} - -/* Pagination */ -.table-pagination { - display: flex; - align-items: center; - justify-content: space-between; - padding: 1rem 1.25rem; - border-top: 1px solid var(--border-color); - background: var(--surface-variant); -} - -.table-pagination-info { - color: var(--text-secondary); - font-size: 0.9rem; -} - -.table-pagination-controls { - display: flex; - gap: 0.5rem; -} - -.table-pagination-btn { - padding: 0.5rem 0.875rem; - border: 1px solid var(--border-color); - background: var(--card-bg); - color: var(--text-secondary); - cursor: pointer; - border-radius: var(--border-radius-sm); - transition: var(--transition); - font-size: 0.9rem; -} - -.table-pagination-btn:hover:not(:disabled) { - background: var(--surface-hover); - border-color: var(--primary-color); - color: var(--primary-color); -} - -.table-pagination-btn:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.table-pagination-btn.active { - background: var(--primary-color); - border-color: var(--primary-color); - color: white; -} - -/* Per Page Selector */ -.table-per-page { - display: flex; - align-items: center; - gap: 0.5rem; - color: var(--text-secondary); - font-size: 0.9rem; -} - -.table-per-page select { - padding: 0.375rem 0.75rem; - border: 1px solid var(--border-color); - border-radius: var(--border-radius-sm); - background: var(--card-bg); - color: var(--text-primary); - cursor: pointer; -} - -/* Column Visibility Dropdown */ -.table-columns-dropdown { - position: absolute; - top: calc(100% + 0.5rem); - right: 0; - background: var(--card-bg); - border: 1px solid var(--border-color); - border-radius: var(--border-radius); - box-shadow: var(--card-shadow-lg); - padding: 0.75rem; - min-width: 200px; - z-index: 100; - opacity: 0; - transform: translateY(-10px); - pointer-events: none; - transition: opacity 0.2s, transform 0.2s; -} - -.table-columns-dropdown.show { - opacity: 1; - transform: translateY(0); - pointer-events: auto; -} - -.table-column-toggle { - display: flex; - align-items: center; - padding: 0.5rem; - cursor: pointer; - border-radius: var(--border-radius-sm); - transition: var(--transition); -} - -.table-column-toggle:hover { - background: var(--surface-hover); -} - -.table-column-toggle input { - margin-right: 0.5rem; -} - -/* Export Menu */ -.table-export-menu { - position: absolute; - top: calc(100% + 0.5rem); - right: 0; - background: var(--card-bg); - border: 1px solid var(--border-color); - border-radius: var(--border-radius); - box-shadow: var(--card-shadow-lg); - min-width: 150px; - z-index: 100; - opacity: 0; - transform: translateY(-10px); - pointer-events: none; - transition: opacity 0.2s, transform 0.2s; -} - -.table-export-menu.show { - opacity: 1; - transform: translateY(0); - pointer-events: auto; -} - -.table-export-option { - padding: 0.75rem 1rem; - cursor: pointer; - transition: var(--transition); - display: flex; - align-items: center; - gap: 0.75rem; - color: var(--text-primary); -} - -.table-export-option:hover { - background: var(--surface-hover); - color: var(--primary-color); -} - -/* Bulk Actions Bar */ -.table-bulk-actions { - display: flex; - align-items: center; - justify-content: space-between; - padding: 0.875rem 1.25rem; - background: var(--primary-50); - border-bottom: 1px solid var(--primary-200); - opacity: 0; - max-height: 0; - overflow: hidden; - transition: all 0.3s ease; -} - -[data-theme="dark"] .table-bulk-actions { - background: var(--primary-900); - border-color: var(--primary-700); -} - -.table-bulk-actions.show { - opacity: 1; - max-height: 100px; -} - -.table-bulk-actions-info { - color: var(--primary-color); - font-weight: 500; -} - -.table-bulk-actions-buttons { - display: flex; - gap: 0.5rem; -} - -/* Empty State */ -.table-empty { - padding: 3rem 2rem; - text-align: center; - color: var(--text-muted); -} - -.table-empty i { - font-size: 3rem; - margin-bottom: 1rem; - opacity: 0.5; -} - -/* Mobile Responsive */ -@media (max-width: 768px) { - .table-toolbar { - flex-direction: column; - align-items: stretch; - } - - .table-toolbar-left, - .table-toolbar-right { - width: 100%; - justify-content: space-between; - } - - .table-search-box { - width: 100%; - } - - /* Card view for mobile */ - .table-enhanced-mobile .table-enhanced thead { - display: none; - } - - .table-enhanced-mobile .table-enhanced tbody tr { - display: block; - margin-bottom: 1rem; - border: 1px solid var(--border-color); - border-radius: var(--border-radius); - padding: 1rem; - } - - .table-enhanced-mobile .table-enhanced tbody td { - display: flex; - justify-content: space-between; - padding: 0.5rem 0; - border: none; - } - - .table-enhanced-mobile .table-enhanced tbody td::before { - content: attr(data-label); - font-weight: 600; - color: var(--text-secondary); - } - - .table-pagination { - flex-direction: column; - gap: 1rem; - } -} - -/* Print Styles */ -@media print { - .table-toolbar, - .table-pagination, - .table-cell-actions, - .table-checkbox-cell { - display: none !important; - } - - .table-enhanced tbody tr:hover { - background: transparent !important; - } -} - diff --git a/app/static/form-bridge.css b/app/static/form-bridge.css new file mode 100644 index 0000000..882ebde --- /dev/null +++ b/app/static/form-bridge.css @@ -0,0 +1,129 @@ +/* Bridge styles to make legacy .form-control inputs match the new UI + Applies generous padding, border, and focus states. */ + +/* Base inputs */ +.form-control, +input.form-control, +select.form-control, +textarea.form-control, +.form-select { + display: block; + width: 100%; + min-height: 2.5rem; /* consistent tap target */ + padding: 0.625rem 0.875rem; /* py-2.5 px-3.5 */ + border: 1px solid #E2E8F0; /* border-light */ + border-radius: 0.5rem; /* rounded-lg */ + background: #FFFFFF; /* card-light */ + color: #2D3748; /* text-light */ + line-height: 1.5; +} + +.form-control:focus, +.form-select:focus { + outline: none; + border-color: #4A90E2; /* primary */ + box-shadow: 0 0 0 2px rgba(74, 144, 226, 0.35); /* focus ring */ +} + +/* Placeholder colors */ +.form-control::placeholder { color: #A0AEC0; } +.dark .form-control::placeholder { color: #718096; } + +/* Textarea */ +textarea.form-control { min-height: 6rem; resize: vertical; } + +/* Sizes */ +.form-control.form-control-sm { min-height: 2.25rem; padding: 0.5rem 0.75rem; } +.form-control.form-control-lg { min-height: 2.875rem; padding: 0.75rem 1rem; } + +/* Dark mode */ +.dark .form-control, +.dark .form-select, +.dark input.form-control, +.dark select.form-control, +.dark textarea.form-control { + background: #2D3748; /* card-dark */ + color: #E2E8F0; /* text-dark */ + border-color: #4A5568; /* border-dark */ +} + +.dark .form-control:focus, +.dark .form-select:focus { + border-color: #4A90E2; + box-shadow: 0 0 0 2px rgba(74, 144, 226, 0.45); +} + +/* Input groups often remove radii; keep padding generous */ +.input-group .form-control { padding-top: 0.625rem; padding-bottom: 0.625rem; } + +/* ============================= + Minimal tokens (fallbacks) + ============================= */ +:root { + --color-primary: #3B82F6; + --color-primary-600: #2563EB; + --color-bg: #F7F9FB; + --color-card: #FFFFFF; + --color-border: #E2E8F0; + --color-text: #1F2937; + --radius-md: 0.5rem; + --shadow-md: 0 8px 24px rgba(0,0,0,0.08); +} +.dark { + --color-bg: #0F172A; + --color-card: #1F2937; + --color-border: #4A5568; + --color-text: #E2E8F0; +} + +/* ============================= + Buttons + ============================= */ +.btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; padding: 0.5rem 0.875rem; border-radius: var(--radius-md); border: 1px solid transparent; font-weight: 600; line-height: 1.25; cursor: pointer; } +.btn:focus { outline: none; box-shadow: 0 0 0 3px rgba(59,130,246,0.35); } +.btn-primary { color: #fff; background-color: var(--color-primary); border-color: var(--color-primary); } +.btn-primary:hover { background-color: var(--color-primary-600); border-color: var(--color-primary-600); } +.btn-secondary { color: var(--color-text); background-color: var(--color-card); border-color: var(--color-border); } +.btn-secondary:hover { background-color: #F3F4F6; } +.btn-ghost { color: var(--color-text); background-color: transparent; border-color: transparent; } +.btn-ghost:hover { background-color: rgba(148,163,184,0.15); } +.btn-sm { padding: 0.375rem 0.625rem; font-size: 0.875rem; } +.btn-lg { padding: 0.625rem 1rem; font-size: 1rem; } +.btn[disabled], .btn.disabled { opacity: .6; cursor: not-allowed; } + +/* ============================= + Focus ring utility + ============================= */ +.focus-ring { outline: none; box-shadow: 0 0 0 3px rgba(59,130,246,0.35); } + +/* ============================= + Table enhancements + ============================= */ +.table { width: 100%; border-collapse: separate; border-spacing: 0; } +.table thead th { position: sticky; top: 0; background: var(--color-card); z-index: 1; } +.table thead th, .table tbody td { padding: 1rem; border-bottom: 1px solid var(--color-border); } +.table-zebra tbody tr:nth-child(odd) { background-color: rgba(148,163,184,0.07); } +.dark .table-zebra tbody tr:nth-child(odd) { background-color: rgba(148,163,184,0.12); } +.table-compact thead th, .table-compact tbody td { padding: 0.625rem 0.75rem; } +.table-number { text-align: right; } + +/* ============================= + Badge chips + ============================= */ +.chip { display: inline-flex; align-items: center; padding: 0.125rem 0.5rem; border-radius: 9999px; font-size: 0.75rem; font-weight: 600; line-height: 1; border: 1px solid transparent; } +.chip-neutral { background: #F1F5F9; color: #334155; } +.dark .chip-neutral { background: #1F2937; color: #E5E7EB; border-color: #374151; } +.chip-success { background: #DCFCE7; color: #166534; } +.dark .chip-success { background: rgba(16,185,129,0.15); color: #34D399; } +.chip-warning { background: #FEF3C7; color: #92400E; } +.dark .chip-warning { background: rgba(245,158,11,0.15); color: #F59E0B; } +.chip-danger { background: #FEE2E2; color: #991B1B; } +.dark .chip-danger { background: rgba(239,68,68,0.15); color: #F87171; } + +/* ============================= + Cards & helpers + ============================= */ +.card { background: var(--color-card); border: 1px solid var(--color-border); border-radius: var(--radius-md); box-shadow: var(--shadow-md); } +.page-bg { background: var(--color-bg); } + + diff --git a/app/static/images/avatar-default.svg b/app/static/images/avatar-default.svg new file mode 100644 index 0000000..29fd62b --- /dev/null +++ b/app/static/images/avatar-default.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/static/keyboard-shortcuts.css b/app/static/keyboard-shortcuts.css deleted file mode 100644 index 0781fca..0000000 --- a/app/static/keyboard-shortcuts.css +++ /dev/null @@ -1,421 +0,0 @@ -/* ========================================================================== - Keyboard Shortcuts & Command Palette - Power user features for navigation and actions - ========================================================================== */ - -/* Command Palette */ -.command-palette { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.5); - backdrop-filter: blur(4px); - z-index: 9999; - display: flex; - align-items: flex-start; - justify-content: center; - padding: 10vh 1rem 1rem; - opacity: 0; - pointer-events: none; - transition: opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1); -} - -.command-palette.show { - opacity: 1; - pointer-events: auto; -} - -[data-theme="dark"] .command-palette { - background: rgba(0, 0, 0, 0.7); -} - -.command-palette-container { - width: 100%; - max-width: 640px; - background: var(--card-bg); - border-radius: 16px; - box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25), - 0 0 0 1px rgba(0, 0, 0, 0.1); - overflow: hidden; - transform: translateY(-20px) scale(0.95); - transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1); -} - -.command-palette.show .command-palette-container { - transform: translateY(0) scale(1); -} - -[data-theme="dark"] .command-palette-container { - background: var(--dark-color); - border: 1px solid var(--border-color); - box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5), - 0 0 0 1px rgba(255, 255, 255, 0.1); -} - -/* Search Input */ -.command-search { - display: flex; - align-items: center; - padding: 1.25rem; - border-bottom: 1px solid var(--border-color); - background: var(--surface-variant); -} - -.command-search-icon { - color: var(--text-muted); - margin-right: 1rem; - font-size: 1.25rem; -} - -.command-search input { - flex: 1; - border: none; - outline: none; - background: transparent; - font-size: 1.125rem; - color: var(--text-primary); -} - -.command-search input::placeholder { - color: var(--text-muted); -} - -/* Results List */ -.command-results { - max-height: 60vh; - overflow-y: auto; -} - -.command-section { - padding: 0.75rem 0; -} - -.command-section-title { - padding: 0.5rem 1.25rem; - font-size: 0.75rem; - font-weight: 600; - text-transform: uppercase; - color: var(--text-muted); - letter-spacing: 0.5px; - background: var(--surface-variant); -} - -/* Command Items */ -.command-item { - display: flex; - align-items: center; - padding: 0.875rem 1.25rem; - cursor: pointer; - transition: all 0.15s ease; - color: var(--text-primary); - border-left: 3px solid transparent; -} - -.command-item:hover, -.command-item.active { - background: var(--surface-hover); -} - -.command-item.active { - border-left-color: var(--primary-color); - background: var(--primary-50); -} - -[data-theme="dark"] .command-item.active { - background: var(--primary-900); - background: rgba(59, 130, 246, 0.1); -} - -.command-item-icon { - width: 36px; - height: 36px; - display: flex; - align-items: center; - justify-content: center; - border-radius: var(--border-radius-sm); - background: var(--surface-variant); - margin-right: 1rem; - flex-shrink: 0; -} - -.command-item:hover .command-item-icon, -.command-item.active .command-item-icon { - background: var(--primary-100); - color: var(--primary-color); -} - -[data-theme="dark"] .command-item:hover .command-item-icon, -[data-theme="dark"] .command-item.active .command-item-icon { - background: var(--primary-900); -} - -.command-item-content { - flex: 1; - min-width: 0; -} - -.command-item-title { - font-weight: 500; - margin-bottom: 0.25rem; -} - -.command-item-description { - font-size: 0.875rem; - color: var(--text-secondary); -} - -.command-item-shortcut { - display: flex; - gap: 0.25rem; - margin-left: auto; - padding-left: 1rem; -} - -.command-kbd { - display: inline-flex; - align-items: center; - justify-content: center; - min-width: 24px; - height: 24px; - padding: 0 0.5rem; - font-size: 0.75rem; - font-family: var(--font-family-mono), 'SF Mono', 'Monaco', 'Consolas', monospace; - font-weight: 600; - color: var(--text-secondary); - background: var(--surface-variant); - border: 1px solid var(--border-color); - border-radius: 5px; - box-shadow: 0 1px 0 0 var(--border-color), - 0 2px 3px rgba(0, 0, 0, 0.1); -} - -.command-item.active .command-kbd { - background: var(--primary-50); - color: var(--primary-color); - border-color: var(--primary-300); - box-shadow: 0 1px 0 0 var(--primary-300); -} - -[data-theme="dark"] .command-item.active .command-kbd { - background: rgba(59, 130, 246, 0.2); - border-color: var(--primary-700); - box-shadow: 0 1px 0 0 var(--primary-700); -} - -/* Empty State */ -.command-empty { - padding: 3rem 2rem; - text-align: center; - color: var(--text-muted); -} - -.command-empty i { - font-size: 2.5rem; - margin-bottom: 1rem; - opacity: 0.5; -} - -/* Footer */ -.command-footer { - padding: 0.875rem 1.25rem; - border-top: 1px solid var(--border-color); - display: flex; - justify-content: space-between; - align-items: center; - background: var(--surface-variant); - font-size: 0.875rem; - color: var(--text-secondary); -} - -.command-footer-actions { - display: flex; - gap: 1.5rem; -} - -.command-footer-action { - display: flex; - align-items: center; - gap: 0.5rem; -} - -/* Keyboard Shortcut Hint */ -.shortcut-hint { - position: fixed; - bottom: 2rem; - right: 2rem; - background: var(--card-bg); - border: 1px solid var(--border-color); - border-radius: var(--border-radius); - padding: 0.75rem 1rem; - box-shadow: var(--card-shadow-lg); - font-size: 0.875rem; - color: var(--text-secondary); - display: flex; - align-items: center; - gap: 0.5rem; - z-index: var(--z-toast); - opacity: 0; - transform: translateY(10px); - pointer-events: none; - transition: opacity 0.3s ease, transform 0.3s ease; -} - -.shortcut-hint.show { - opacity: 1; - transform: translateY(0); -} - -.shortcut-hint-close { - background: none; - border: none; - color: var(--text-muted); - cursor: pointer; - padding: 0; - margin-left: 0.5rem; -} - -.shortcut-hint-close:hover { - color: var(--text-primary); -} - -/* Help Modal for All Shortcuts */ -.shortcuts-help-modal .modal-content { - max-height: 80vh; - overflow-y: auto; -} - -.shortcuts-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); - gap: 1.5rem; - margin-top: 1rem; -} - -.shortcuts-category { - background: var(--surface-variant); - border-radius: var(--border-radius); - padding: 1.25rem; -} - -.shortcuts-category-title { - font-weight: 600; - margin-bottom: 1rem; - color: var(--primary-color); - display: flex; - align-items: center; - gap: 0.5rem; -} - -.shortcut-row { - display: flex; - justify-content: space-between; - align-items: center; - padding: 0.75rem 0; - border-bottom: 1px solid var(--border-light); -} - -.shortcut-row:last-child { - border-bottom: none; -} - -.shortcut-label { - color: var(--text-primary); - font-size: 0.9rem; -} - -.shortcut-keys { - display: flex; - gap: 0.25rem; -} - -/* Quick Action Buttons with Shortcuts */ -.btn-with-shortcut { - position: relative; - display: inline-flex; - align-items: center; - gap: 0.5rem; -} - -.btn-with-shortcut .shortcut-badge { - font-size: 0.7rem; - padding: 0.125rem 0.375rem; - background: rgba(255, 255, 255, 0.2); - border-radius: 3px; - font-family: var(--font-family-mono); -} - -/* Keyboard Navigation Indicator */ -body.keyboard-navigation *:focus { - outline: 2px solid var(--primary-color); - outline-offset: 2px; -} - -body:not(.keyboard-navigation) *:focus { - outline: none; -} - -/* Mobile Responsive */ -@media (max-width: 768px) { - .command-palette { - padding: 1rem; - } - - .command-palette-container { - max-width: 100%; - } - - .command-results { - max-height: 50vh; - } - - .command-item-shortcut { - display: none; - } - - .command-footer-actions { - display: none; - } - - .shortcut-hint { - display: none; - } - - .shortcuts-grid { - grid-template-columns: 1fr; - } -} - -/* Scrollbar Styling */ -.command-results::-webkit-scrollbar { - width: 8px; -} - -.command-results::-webkit-scrollbar-track { - background: var(--surface-variant); -} - -.command-results::-webkit-scrollbar-thumb { - background: var(--border-color); - border-radius: 4px; -} - -.command-results::-webkit-scrollbar-thumb:hover { - background: var(--text-muted); -} - -/* Animation */ -@keyframes command-pulse { - 0%, 100% { - transform: scale(1); - } - 50% { - transform: scale(1.05); - } -} - -.command-item-icon.pulse { - animation: command-pulse 0.5s ease; -} - diff --git a/app/static/loading-states.css b/app/static/loading-states.css deleted file mode 100644 index 31fb959..0000000 --- a/app/static/loading-states.css +++ /dev/null @@ -1,435 +0,0 @@ -/* ========================================================================== - Loading States & Skeleton Screens - Modern loading indicators and skeleton components for better UX - ========================================================================== */ - -/* Skeleton Base Styles */ -.skeleton { - background: linear-gradient( - 90deg, - var(--gray-200) 0%, - var(--gray-100) 50%, - var(--gray-200) 100% - ); - background-size: 200% 100%; - animation: skeleton-loading 1.5s ease-in-out infinite; - border-radius: var(--border-radius-sm); - position: relative; - overflow: hidden; -} - -[data-theme="dark"] .skeleton { - background: linear-gradient( - 90deg, - var(--gray-800) 0%, - var(--gray-700) 50%, - var(--gray-800) 100% - ); - background-size: 200% 100%; -} - -@keyframes skeleton-loading { - 0% { - background-position: 200% 0; - } - 100% { - background-position: -200% 0; - } -} - -/* Skeleton Variants */ -.skeleton-text { - height: 1rem; - margin-bottom: 0.5rem; - border-radius: var(--border-radius-xs); -} - -.skeleton-text-lg { - height: 1.5rem; - margin-bottom: 0.75rem; -} - -.skeleton-title { - height: 2rem; - width: 60%; - margin-bottom: 1rem; -} - -.skeleton-avatar { - width: 40px; - height: 40px; - border-radius: 50%; -} - -.skeleton-avatar-lg { - width: 64px; - height: 64px; - border-radius: 50%; -} - -.skeleton-card { - height: 200px; - border-radius: var(--border-radius); -} - -.skeleton-button { - height: 38px; - width: 100px; - border-radius: var(--border-radius-sm); -} - -.skeleton-input { - height: 42px; - border-radius: var(--border-radius-sm); -} - -.skeleton-icon { - width: 24px; - height: 24px; - border-radius: var(--border-radius-xs); -} - -.skeleton-badge { - height: 24px; - width: 60px; - border-radius: var(--border-radius-full); -} - -/* Table Skeleton */ -.skeleton-table { - width: 100%; -} - -.skeleton-table-row { - display: flex; - gap: 1rem; - padding: 1rem; - border-bottom: 1px solid var(--border-color); -} - -.skeleton-table-cell { - flex: 1; -} - -/* Card Skeleton */ -.skeleton-summary-card { - padding: 1.5rem; - background: var(--card-bg); - border-radius: var(--border-radius); - box-shadow: var(--card-shadow); -} - -.skeleton-summary-card-icon { - width: 48px; - height: 48px; - border-radius: 50%; - margin-bottom: 1rem; -} - -.skeleton-summary-card-label { - height: 1rem; - width: 60%; - margin-bottom: 0.5rem; -} - -.skeleton-summary-card-value { - height: 2rem; - width: 40%; -} - -/* Loading Spinner */ -.loading-spinner { - display: inline-block; - width: 20px; - height: 20px; - border: 3px solid var(--gray-300); - border-radius: 50%; - border-top-color: var(--primary-color); - animation: spinner-rotate 0.8s linear infinite; -} - -[data-theme="dark"] .loading-spinner { - border-color: var(--gray-600); - border-top-color: var(--primary-color); -} - -.loading-spinner-lg { - width: 40px; - height: 40px; - border-width: 4px; -} - -.loading-spinner-sm { - width: 16px; - height: 16px; - border-width: 2px; -} - -@keyframes spinner-rotate { - to { - transform: rotate(360deg); - } -} - -/* Loading Overlay */ -.loading-overlay { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(255, 255, 255, 0.9); - backdrop-filter: blur(4px); - display: flex; - align-items: center; - justify-content: center; - z-index: 10; - border-radius: inherit; - opacity: 0; - animation: fade-in 0.3s ease forwards; -} - -[data-theme="dark"] .loading-overlay { - background: rgba(15, 23, 42, 0.9); -} - -@keyframes fade-in { - to { - opacity: 1; - } -} - -.loading-overlay-content { - text-align: center; - color: var(--text-primary); -} - -.loading-overlay-spinner { - margin: 0 auto 1rem; -} - -/* Pulse Animation */ -.pulse { - animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; -} - -@keyframes pulse { - 0%, 100% { - opacity: 1; - } - 50% { - opacity: 0.5; - } -} - -/* Shimmer Effect */ -.shimmer { - position: relative; - overflow: hidden; -} - -.shimmer::after { - content: ''; - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - transform: translateX(-100%); - background: linear-gradient( - 90deg, - rgba(255, 255, 255, 0) 0, - rgba(255, 255, 255, 0.3) 50%, - rgba(255, 255, 255, 0) 100% - ); - animation: shimmer 2s infinite; -} - -[data-theme="dark"] .shimmer::after { - background: linear-gradient( - 90deg, - rgba(255, 255, 255, 0) 0, - rgba(255, 255, 255, 0.1) 50%, - rgba(255, 255, 255, 0) 100% - ); -} - -@keyframes shimmer { - 100% { - transform: translateX(100%); - } -} - -/* Progress Bar */ -.progress-bar-animated { - position: relative; - overflow: hidden; -} - -.progress-bar-animated::after { - content: ''; - position: absolute; - top: 0; - left: 0; - bottom: 0; - width: 100%; - background: linear-gradient( - 90deg, - transparent, - rgba(255, 255, 255, 0.3), - transparent - ); - animation: progress-shine 1.5s infinite; -} - -@keyframes progress-shine { - 0% { - transform: translateX(-100%); - } - 100% { - transform: translateX(100%); - } -} - -/* Loading Dots */ -.loading-dots { - display: inline-flex; - gap: 0.25rem; -} - -.loading-dots span { - width: 8px; - height: 8px; - border-radius: 50%; - background: var(--primary-color); - animation: loading-dots 1.4s ease-in-out infinite; -} - -.loading-dots span:nth-child(1) { - animation-delay: -0.32s; -} - -.loading-dots span:nth-child(2) { - animation-delay: -0.16s; -} - -@keyframes loading-dots { - 0%, 80%, 100% { - transform: scale(0); - opacity: 0.5; - } - 40% { - transform: scale(1); - opacity: 1; - } -} - -/* Skeleton List */ -.skeleton-list-item { - display: flex; - align-items: center; - gap: 1rem; - padding: 1rem; - border-bottom: 1px solid var(--border-color); -} - -.skeleton-list-item:last-child { - border-bottom: none; -} - -/* Content Placeholder */ -.content-placeholder { - min-height: 200px; - display: flex; - align-items: center; - justify-content: center; - background: var(--surface-variant); - border-radius: var(--border-radius); - padding: 2rem; -} - -/* Loading State Classes */ -.is-loading { - pointer-events: none; - opacity: 0.6; - position: relative; -} - -.is-loading::after { - content: ''; - position: absolute; - top: 50%; - left: 50%; - width: 24px; - height: 24px; - margin: -12px 0 0 -12px; - border: 3px solid var(--gray-300); - border-radius: 50%; - border-top-color: var(--primary-color); - animation: spinner-rotate 0.8s linear infinite; -} - -/* Button Loading State */ -.btn-loading { - position: relative; - color: transparent !important; - pointer-events: none; -} - -.btn-loading::after { - content: ''; - position: absolute; - top: 50%; - left: 50%; - width: 16px; - height: 16px; - margin: -8px 0 0 -8px; - border: 2px solid currentColor; - border-radius: 50%; - border-top-color: transparent; - animation: spinner-rotate 0.6s linear infinite; - opacity: 0.7; -} - -/* Skeleton Chart */ -.skeleton-chart { - height: 300px; - background: var(--card-bg); - border-radius: var(--border-radius); - padding: 1rem; - display: flex; - align-items: flex-end; - gap: 0.5rem; -} - -.skeleton-chart-bar { - flex: 1; - background: var(--gray-200); - border-radius: var(--border-radius-xs); - animation: skeleton-loading 1.5s ease-in-out infinite; -} - -[data-theme="dark"] .skeleton-chart-bar { - background: var(--gray-700); -} - -.skeleton-chart-bar:nth-child(1) { height: 60%; } -.skeleton-chart-bar:nth-child(2) { height: 80%; } -.skeleton-chart-bar:nth-child(3) { height: 45%; } -.skeleton-chart-bar:nth-child(4) { height: 90%; } -.skeleton-chart-bar:nth-child(5) { height: 70%; } -.skeleton-chart-bar:nth-child(6) { height: 55%; } -.skeleton-chart-bar:nth-child(7) { height: 85%; } - -/* Responsive Skeleton */ -@media (max-width: 768px) { - .skeleton-summary-card { - padding: 1rem; - } - - .skeleton-table-row { - flex-direction: column; - gap: 0.5rem; - } -} - diff --git a/app/static/micro-interactions.css b/app/static/micro-interactions.css deleted file mode 100644 index 8a0c898..0000000 --- a/app/static/micro-interactions.css +++ /dev/null @@ -1,586 +0,0 @@ -/* ========================================================================== - Micro-Interactions & Animations - Subtle animations and interactions for enhanced UX - ========================================================================== */ - -/* Ripple Effect */ -.ripple { - position: relative; - overflow: hidden; -} - -.ripple::before { - content: ''; - position: absolute; - top: 50%; - left: 50%; - width: 0; - height: 0; - border-radius: 50%; - background: rgba(255, 255, 255, 0.5); - transform: translate(-50%, -50%); - transition: width 0.6s, height 0.6s; -} - -.ripple:active::before { - width: 300px; - height: 300px; - opacity: 0; -} - -[data-theme="dark"] .ripple::before { - background: rgba(255, 255, 255, 0.2); -} - -/* Button Ripple Effect */ -.btn-ripple { - position: relative; - overflow: hidden; - transition: var(--transition); -} - -.btn-ripple::after { - content: ''; - position: absolute; - top: 50%; - left: 50%; - width: 0; - height: 0; - border-radius: 50%; - background: rgba(255, 255, 255, 0.5); - transform: translate(-50%, -50%); - transition: width 0.5s, height 0.5s, opacity 0.5s; - opacity: 0; -} - -.btn-ripple:active::after { - width: 200px; - height: 200px; - opacity: 1; - transition: 0s; -} - -/* Smooth Scale on Hover */ -.scale-hover { - transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1); -} - -.scale-hover:hover { - transform: scale(1.05); -} - -.scale-hover:active { - transform: scale(0.98); -} - -/* Lift Effect on Hover */ -.lift-hover { - transition: transform 0.2s ease, box-shadow 0.2s ease; -} - -.lift-hover:hover { - transform: translateY(-4px); - box-shadow: var(--card-shadow-hover); -} - -/* Icon Animations */ -.icon-spin-hover { - transition: transform 0.3s ease; -} - -.icon-spin-hover:hover { - transform: rotate(15deg); -} - -.icon-bounce { - animation: icon-bounce 0.5s ease; -} - -@keyframes icon-bounce { - 0%, 100% { - transform: translateY(0); - } - 50% { - transform: translateY(-10px); - } -} - -.icon-pulse { - animation: icon-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; -} - -@keyframes icon-pulse { - 0%, 100% { - opacity: 1; - } - 50% { - opacity: 0.5; - } -} - -.icon-shake { - animation: icon-shake 0.5s ease; -} - -@keyframes icon-shake { - 0%, 100% { - transform: translateX(0); - } - 10%, 30%, 50%, 70%, 90% { - transform: translateX(-5px); - } - 20%, 40%, 60%, 80% { - transform: translateX(5px); - } -} - -/* Count Up Animation */ -.count-up { - animation: count-up 0.5s ease-out; -} - -@keyframes count-up { - from { - opacity: 0; - transform: translateY(20px) scale(0.8); - } - to { - opacity: 1; - transform: translateY(0) scale(1); - } -} - -/* Fade Animations */ -.fade-in { - animation: fade-in 0.3s ease-in; -} - -@keyframes fade-in { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -.fade-in-up { - animation: fade-in-up 0.4s ease-out; -} - -@keyframes fade-in-up { - from { - opacity: 0; - transform: translateY(20px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -.fade-in-down { - animation: fade-in-down 0.4s ease-out; -} - -@keyframes fade-in-down { - from { - opacity: 0; - transform: translateY(-20px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -.fade-in-left { - animation: fade-in-left 0.4s ease-out; -} - -@keyframes fade-in-left { - from { - opacity: 0; - transform: translateX(-20px); - } - to { - opacity: 1; - transform: translateX(0); - } -} - -.fade-in-right { - animation: fade-in-right 0.4s ease-out; -} - -@keyframes fade-in-right { - from { - opacity: 0; - transform: translateX(20px); - } - to { - opacity: 1; - transform: translateX(0); - } -} - -/* Slide Animations */ -.slide-in-up { - animation: slide-in-up 0.3s cubic-bezier(0.4, 0, 0.2, 1); -} - -@keyframes slide-in-up { - from { - transform: translateY(100%); - } - to { - transform: translateY(0); - } -} - -/* Zoom Animations */ -.zoom-in { - animation: zoom-in 0.3s cubic-bezier(0.4, 0, 0.2, 1); -} - -@keyframes zoom-in { - from { - opacity: 0; - transform: scale(0.9); - } - to { - opacity: 1; - transform: scale(1); - } -} - -/* Bounce Animation */ -.bounce-in { - animation: bounce-in 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); -} - -@keyframes bounce-in { - 0% { - opacity: 0; - transform: scale(0.3); - } - 50% { - opacity: 1; - transform: scale(1.05); - } - 70% { - transform: scale(0.95); - } - 100% { - transform: scale(1); - } -} - -/* Card Flip */ -.card-flip { - transition: transform 0.6s; - transform-style: preserve-3d; -} - -.card-flip:hover { - transform: rotateY(5deg); -} - -/* Glow Effect */ -.glow-hover { - transition: box-shadow 0.3s ease; -} - -.glow-hover:hover { - box-shadow: 0 0 20px rgba(59, 130, 246, 0.4); -} - -/* Progress Ring Animation */ -@keyframes progress-ring { - 0% { - stroke-dashoffset: 251.2; - } - 100% { - stroke-dashoffset: 0; - } -} - -/* Notification Badge Pulse */ -.badge-pulse { - position: relative; -} - -.badge-pulse::after { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - border-radius: inherit; - background: inherit; - animation: badge-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; -} - -@keyframes badge-pulse { - 0%, 100% { - opacity: 1; - transform: scale(1); - } - 50% { - opacity: 0; - transform: scale(1.5); - } -} - -/* Skeleton Shimmer */ -.shimmer-effect { - background: linear-gradient( - 90deg, - transparent 0%, - rgba(255, 255, 255, 0.1) 50%, - transparent 100% - ); - background-size: 200% 100%; - animation: shimmer-move 2s infinite; -} - -@keyframes shimmer-move { - 0% { - background-position: -200% 0; - } - 100% { - background-position: 200% 0; - } -} - -/* Typewriter Effect */ -.typewriter { - overflow: hidden; - border-right: 0.15em solid var(--primary-color); - white-space: nowrap; - animation: typewriter 3.5s steps(40, end), blink-caret 0.75s step-end infinite; -} - -@keyframes typewriter { - from { - width: 0; - } - to { - width: 100%; - } -} - -@keyframes blink-caret { - from, to { - border-color: transparent; - } - 50% { - border-color: var(--primary-color); - } -} - -/* Number Counter */ -.number-counter { - display: inline-block; - transition: all 0.5s ease; -} - -.number-counter.updated { - color: var(--success-color); - transform: scale(1.2); - animation: number-pop 0.5s ease; -} - -@keyframes number-pop { - 0% { - transform: scale(1); - } - 50% { - transform: scale(1.3); - } - 100% { - transform: scale(1); - } -} - -/* Success Checkmark */ -.success-checkmark { - width: 80px; - height: 80px; - margin: 0 auto; -} - -.success-checkmark .check-icon { - width: 80px; - height: 80px; - position: relative; - border-radius: 50%; - box-sizing: content-box; - border: 4px solid var(--success-color); -} - -.success-checkmark .check-icon::before { - top: 3px; - left: -2px; - width: 30px; - transform-origin: 100% 50%; - border-radius: 100px 0 0 100px; -} - -.success-checkmark .check-icon::after { - top: 0; - left: 30px; - width: 60px; - transform-origin: 0 50%; - border-radius: 0 100px 100px 0; - animation: rotate-circle 4.25s ease-in; -} - -.success-checkmark .check-icon .icon-line { - height: 5px; - background-color: var(--success-color); - display: block; - border-radius: 2px; - position: absolute; - z-index: 10; -} - -.success-checkmark .check-icon .icon-line.line-tip { - top: 46px; - left: 14px; - width: 25px; - transform: rotate(45deg); - animation: icon-line-tip 0.75s; -} - -.success-checkmark .check-icon .icon-line.line-long { - top: 38px; - right: 8px; - width: 47px; - transform: rotate(-45deg); - animation: icon-line-long 0.75s; -} - -.success-checkmark .check-icon .icon-circle { - top: -4px; - left: -4px; - z-index: 10; - width: 80px; - height: 80px; - border-radius: 50%; - position: absolute; - box-sizing: content-box; - border: 4px solid rgba(76, 175, 80, 0.5); -} - -.success-checkmark .check-icon .icon-fix { - top: 8px; - width: 5px; - left: 26px; - z-index: 1; - height: 85px; - position: absolute; - transform: rotate(-45deg); - background-color: var(--card-bg); -} - -@keyframes rotate-circle { - 0% { - transform: rotate(-45deg); - } - 5% { - transform: rotate(-45deg); - } - 12% { - transform: rotate(-405deg); - } - 100% { - transform: rotate(-405deg); - } -} - -@keyframes icon-line-tip { - 0% { - width: 0; - left: 1px; - top: 19px; - } - 54% { - width: 0; - left: 1px; - top: 19px; - } - 70% { - width: 50px; - left: -8px; - top: 37px; - } - 84% { - width: 17px; - left: 21px; - top: 48px; - } - 100% { - width: 25px; - left: 14px; - top: 45px; - } -} - -@keyframes icon-line-long { - 0% { - width: 0; - right: 46px; - top: 54px; - } - 65% { - width: 0; - right: 46px; - top: 54px; - } - 84% { - width: 55px; - right: 0px; - top: 35px; - } - 100% { - width: 47px; - right: 8px; - top: 38px; - } -} - -/* Focus Ring Enhancement */ -.focus-ring-enhanced:focus { - outline: none; - box-shadow: 0 0 0 3px var(--primary-color), 0 0 0 5px rgba(59, 130, 246, 0.2); - transition: box-shadow 0.2s ease; -} - -/* Stagger Animation */ -.stagger-animation > * { - opacity: 0; - animation: fade-in-up 0.5s ease forwards; -} - -.stagger-animation > *:nth-child(1) { animation-delay: 0.05s; } -.stagger-animation > *:nth-child(2) { animation-delay: 0.1s; } -.stagger-animation > *:nth-child(3) { animation-delay: 0.15s; } -.stagger-animation > *:nth-child(4) { animation-delay: 0.2s; } -.stagger-animation > *:nth-child(5) { animation-delay: 0.25s; } -.stagger-animation > *:nth-child(6) { animation-delay: 0.3s; } -.stagger-animation > *:nth-child(7) { animation-delay: 0.35s; } -.stagger-animation > *:nth-child(8) { animation-delay: 0.4s; } - -/* Reduce Motion Support */ -@media (prefers-reduced-motion: reduce) { - *, - *::before, - *::after { - animation-duration: 0.01ms !important; - animation-iteration-count: 1 !important; - transition-duration: 0.01ms !important; - } -} - diff --git a/app/static/mobile.css b/app/static/mobile.css deleted file mode 100644 index 6bfaad6..0000000 --- a/app/static/mobile.css +++ /dev/null @@ -1,1296 +0,0 @@ -/* Enhanced Mobile-First CSS for TimeTracker */ - -/* Mobile-specific variables */ -/* Force mobile dropdown styles with high specificity */ -:root { - --mobile-touch-target: 52px; - --mobile-nav-height: 70px; - --mobile-tabbar-height: 64px; - --mobile-card-padding: 1.25rem; - --mobile-button-height: 52px; - --mobile-input-height: 56px; - --mobile-section-spacing: 1.5rem; - --mobile-card-spacing: 1rem; - --mobile-border-radius: 4px; - --mobile-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - --mobile-shadow-hover: 0 4px 16px rgba(0, 0, 0, 0.15); -} - -/* Enhanced Mobile-specific improvements - Modern Touch Interface */ -@media (max-width: 768px) { - /* Prevent content from being hidden behind the tab bar */ - main { - padding-bottom: calc(var(--mobile-section-spacing) + var(--mobile-tabbar-height) + env(safe-area-inset-bottom)); - padding-top: 1rem; - scroll-padding-top: var(--mobile-nav-height); - } - - /* Improved body padding for mobile with safe areas */ - body { - padding-top: env(safe-area-inset-top); - padding-bottom: env(safe-area-inset-bottom); - padding-left: env(safe-area-inset-left); - padding-right: env(safe-area-inset-right); - overscroll-behavior: none; - -webkit-overflow-scrolling: touch; - } - - /* Container improvements */ - .container, .container-fluid { - padding-left: 1rem; - padding-right: 1rem; - max-width: 100%; - } - - /* Enhanced Row and Column Layout */ - .row { - margin-left: -0.5rem; - margin-right: -0.5rem; - } - - .col, .col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12 { - padding-left: 0.5rem; - padding-right: 0.5rem; - margin-bottom: var(--mobile-card-spacing); - } - - .col:last-child { - margin-bottom: 0; - } - - /* Enhanced Card Layout - Modern Mobile Design */ - .card { - margin-bottom: var(--mobile-card-spacing); - border-radius: var(--border-radius); - box-shadow: var(--mobile-shadow); - border: 1px solid var(--border-color); - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - background: var(--card-bg); - overflow: hidden; - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); - touch-action: manipulation; - -webkit-tap-highlight-color: transparent; - } - - /* Only interactive cards (links, buttons) should have hover effects */ - .card a:active, - .card.hover-lift:active { - box-shadow: var(--mobile-shadow-hover); - transform: translateY(0) scale(0.99); - transition: all 0.15s ease; - opacity: 0.95; - } - - .card-body { - padding: var(--mobile-card-padding); - } - - .card-header { - padding: 1.25rem var(--mobile-card-padding); - border-bottom: 1px solid var(--border-color); - background: var(--light-color); - } - - /* Enhanced Button Layout - Modern Touch Interface */ - .btn { - min-height: var(--mobile-button-height); - padding: 1rem 1.5rem; - font-size: 1rem; - border-radius: var(--border-radius); - font-weight: var(--font-weight-medium); - display: inline-flex; - align-items: center; - justify-content: center; - text-decoration: none; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - -webkit-tap-highlight-color: transparent; - width: 100%; - margin-bottom: 0.75rem; - gap: 0.5rem; - position: relative; - overflow: hidden; - touch-action: manipulation; - user-select: none; - font-family: var(--font-family-sans); - letter-spacing: 0.025em; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - } - - /* Enhanced button interactions */ - .btn::before { - content: ''; - position: absolute; - top: 50%; - left: 50%; - width: 0; - height: 0; - border-radius: 50%; - background: rgba(255, 255, 255, 0.3); - transform: translate(-50%, -50%); - transition: width 0.6s, height 0.6s; - z-index: 0; - } - - .btn:active::before { - width: 300px; - height: 300px; - } - - .btn > * { - position: relative; - z-index: 1; - } - - .btn:hover { - transform: translateY(-2px); - box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); - } - - .btn:active { - transform: translateY(0) scale(0.98); - transition: all 0.15s ease; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); - } - - /* Enhanced touch feedback */ - @media (hover: none) and (pointer: coarse) { - .btn:active { - background-color: var(--surface-pressed); - transform: scale(0.95); - } - - .btn-primary:active { - background: var(--primary-700); - } - } - - /* icon colors inherit from base button styles */ - - .btn:last-child { - margin-bottom: 0; - } - - .btn-sm { - min-height: 44px; - padding: 0.875rem 1.25rem; - font-size: 0.9rem; - } - - .btn-sm:hover { - background: #f3f4f6; - border-color: #4b5563; - color: #4b5563; - } - - .btn-lg { - min-height: 60px; - padding: 1.25rem 2rem; - font-size: 1.125rem; - } - - .btn-lg:hover { - background: #f3f4f6; - border-color: #4b5563; - color: #4b5563; - } - - /* Enhanced Button Group Layout */ - .btn-group { - display: flex; - flex-direction: column; - width: 100%; - gap: 0.75rem; - } - - .btn-group .btn { - border-radius: var(--mobile-border-radius) !important; - margin-bottom: 0; - width: 100%; - } - - /* Enhanced Form Layout */ - .form-control, .form-select { - min-height: var(--mobile-input-height); - padding: 1rem 1.25rem; - font-size: 16px; /* Prevents zoom on iOS */ - border-radius: var(--mobile-border-radius); - border: 1px solid var(--border-color); - transition: all 0.3s ease; - background: var(--bs-body-bg, #ffffff); - width: 100%; - } - - .form-control:focus, .form-select:focus { - border-color: #6b7280; /* consistent grey focus from base */ - box-shadow: 0 0 0 4px rgba(107, 114, 128, 0.1); - outline: none; - transform: translateY(-1px); - } - - .form-label { - font-weight: 600; - color: var(--text-primary); - margin-bottom: 0.75rem; - font-size: 0.95rem; - display: block; - } - - .form-text { - font-size: 0.875rem; - color: var(--text-muted); - margin-top: 0.5rem; - } - - /* Enhanced Table Layout for Mobile */ - .table-responsive { - border: none; - border-radius: var(--mobile-border-radius); - overflow: visible !important; /* Allow dropdowns to overflow */ - margin-bottom: var(--mobile-card-spacing); - } - - .table { - display: block; - width: 100%; - margin-bottom: 0; - } - - .table thead { - display: none; - } - - .table tbody { - display: block; - width: 100%; - } - - .table tr { - display: block; - margin-bottom: 1rem; - border: 1px solid var(--border-color); - border-radius: var(--mobile-border-radius); - background: var(--bs-card-bg, #ffffff); - box-shadow: var(--mobile-shadow); - overflow: hidden; - transition: all 0.3s ease; - } - - .table tr:hover { - box-shadow: var(--mobile-shadow-hover); - transform: translateY(-1px); - } - - .table td { - display: block; - text-align: left; - padding: 1rem; - border: none; - border-bottom: 1px solid var(--border-color); - position: relative; - background: var(--bs-card-bg, #ffffff); - } - - .table td:last-child { - border-bottom: none; - } - - .table td:before { - content: attr(data-label) ": "; - font-weight: 600; - color: var(--text-primary); - display: block; - margin-bottom: 0.5rem; - font-size: 0.875rem; - text-transform: uppercase; - letter-spacing: 0.5px; - color: var(--text-muted); - } - - .table td.actions-cell { - text-align: left; - padding: 1rem; - background: var(--light-color); - } - - .table td.actions-cell:before { - display: block; - } - - /* Enhanced Navigation Layout - Modern Mobile Glass Effect */ - .navbar { - min-height: var(--mobile-nav-height); - padding: 0.5rem 0; - background: rgba(255, 255, 255, 0.95) !important; - backdrop-filter: blur(12px) !important; - -webkit-backdrop-filter: blur(12px) !important; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - border-bottom: 1px solid var(--border-light); - position: sticky; - top: 0; - z-index: var(--z-fixed); - } - - .navbar-brand { - font-size: 1.25rem; - font-weight: 700; - } - - .navbar-toggler { - border: none; - padding: 0.5rem; - min-height: var(--mobile-touch-target); - min-width: var(--mobile-touch-target); - border-radius: var(--mobile-border-radius); - background: #f8fafc; - } - - .navbar-toggler:focus { - box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1); - } - - .navbar-collapse { - background: var(--bs-body-bg, #ffffff); - border-top: 1px solid var(--border-color); - margin-top: 0.75rem; - padding: 1rem 0; - box-shadow: 0 8px 20px rgba(0, 0, 0, 0.35); - border-radius: 0; - position: relative; - z-index: 1100; /* above page content */ - } - - .navbar-nav .nav-link { - padding: 0.875rem 1rem; - margin: 0.25rem 0; - border-radius: 0; - font-size: 1rem; - min-height: var(--mobile-touch-target); - display: flex; - align-items: center; - gap: 0.5rem; - transition: all 0.3s ease; - } - - .navbar-nav .nav-link:hover { - background: var(--light-color); - transform: translateX(4px); - } - - .navbar-nav .nav-link.active { - background: #6b7280; - color: #ffffff !important; - box-shadow: 0 4px 12px rgba(107, 114, 128, 0.3); - } - - .navbar-nav .nav-link i { - width: 24px; - text-align: center; - font-size: 1.1rem; - } - - /* Enhanced Dropdown Layout (navbar only - mobile breakpoint) */ - body.mobile-view .navbar .dropdown-menu { - position: static !important; - float: none; - width: 100%; - margin: 0; - border: 1px solid var(--border-color) !important; - box-shadow: 0 8px 25px rgba(0, 0, 0, 0.25) !important; - background: var(--bs-dropdown-bg, #ffffff) !important; - background-color: var(--bs-dropdown-bg, #ffffff) !important; /* ensure solid bg */ - border-radius: var(--mobile-border-radius); - margin-top: 0.75rem; - padding: 0.75rem 0.25rem; /* Add padding to prevent outline clipping */ - backdrop-filter: none; - -webkit-backdrop-filter: none; - isolation: isolate; /* prevent blending with backdrop */ - z-index: 1070 !important; /* below fixed navbar but above content */ - overflow: visible !important; /* Allow outlines to show */ - } - - /* Ensure table dropdowns work properly on mobile */ - .table .dropdown-menu { - position: absolute !important; - z-index: 1070 !important; - width: auto !important; - min-width: 160px; - left: auto !important; - right: 0 !important; - } - - .table .dropdown.show { - z-index: 1100 !important; - } - - .dropdown-item { - padding: 0.875rem 1.25rem; - border-radius: var(--mobile-border-radius); - margin: 0.25rem 0.25rem; /* Add margin for outline space */ - min-height: var(--mobile-touch-target); - display: flex; - align-items: center; - gap: 0.75rem; - transition: all 0.3s ease; - color: var(--bs-dropdown-link-color, var(--text-primary)) !important; - background: var(--bs-dropdown-bg, #ffffff) !important; /* ensure solid bg for items */ - border: none; - text-decoration: none; - font-weight: 600; - font-size: 1rem; - text-shadow: none; - } - - .dropdown-item:hover { - background: var(--bs-dropdown-link-hover-bg, #f1f5f9) !important; - color: var(--text-primary, #0f172a) !important; - transform: translateX(4px); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - } - - .dropdown-item:active { - background: #e2e8f0 !important; - transform: scale(0.98); - } - - .dropdown-divider { - border-top: 1px solid #e2e8f0 !important; - margin: 0.5rem 0; - opacity: 1; - } - - /* Enhanced dropdown toggle button */ - .dropdown-toggle { - background: var(--dropdown-bg) !important; - border: 1px solid var(--border-color) !important; - color: var(--text-primary) !important; - font-weight: 500 !important; - padding: 0.75rem 1rem !important; - border-radius: var(--mobile-border-radius) !important; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important; - text-decoration: none !important; - display: flex !important; - align-items: center !important; - justify-content: space-between !important; - width: 100% !important; - min-height: var(--mobile-touch-target) !important; - } - - .dropdown-toggle:hover { - background: var(--light-color) !important; - border-color: var(--border-color) !important; - color: var(--text-primary) !important; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15) !important; - } - - .dropdown-toggle:focus { - background: var(--dropdown-bg) !important; - border-color: #6b7280 !important; - color: #6b7280 !important; - box-shadow: 0 0 0 4px rgba(107, 114, 128, 0.1) !important; - outline: 2px solid #6b7280 !important; - outline-offset: 2px !important; - } - - .dropdown-toggle::after { - border-top-color: var(--text-muted) !important; - margin-left: 0.5rem !important; - border-width: 0.3em 0.3em 0 !important; - } - - /* Ensure navbar dropdown is visible when open */ - body.mobile-view .navbar .dropdown.show .dropdown-menu { - display: block !important; - transform: none !important; - } - - /* Improve dropdown accessibility (navbar only) */ - body.mobile-view .navbar .dropdown-menu[data-bs-popper] { - position: static !important; - transform: none !important; - } - - /* Override Bootstrap dropdown styles (navbar only) */ - body.mobile-view .navbar .dropdown-menu.show { - display: block !important; - transform: none !important; - background: var(--bs-dropdown-bg, #ffffff) !important; - border: 1px solid var(--border-color) !important; - box-shadow: 0 8px 25px rgba(0, 0, 0, 0.25) !important; - } - - /* Keep visibility overrides within mobile breakpoint context only */ - body.mobile-view .navbar .dropdown.show .dropdown-menu, - body.mobile-view .navbar .dropdown-menu.show, - body.mobile-view .navbar .dropdown-menu[data-bs-popper="static"] { - display: block !important; - background: var(--bs-dropdown-bg, #ffffff) !important; - border: 1px solid var(--border-color) !important; - box-shadow: 0 8px 25px rgba(0, 0, 0, 0.25) !important; - z-index: 1070 !important; - } - - /* Additional dropdown overrides for Bootstrap (navbar only) */ - body.mobile-view .navbar .dropdown-menu[data-bs-popper="static"], - body.mobile-view .navbar .dropdown-menu[data-bs-popper="dynamic"] { - position: static !important; - transform: none !important; - inset: auto !important; - margin: 0.75rem 0 0 0 !important; - } - - /* Ensure dropdown container is visible and clickable */ - body.mobile-view .dropdown { - position: relative !important; - } - - /* Force dropdown to open instead of collapsing the whole navbar */ - body.mobile-view .navbar .dropdown-toggle[aria-expanded="true"] + .dropdown-menu { - display: block !important; - } - /* Override any Bootstrap positioning */ - body.mobile-view .navbar .dropdown-menu.dropdown-menu-end { - right: auto !important; - left: auto !important; - position: static !important; - } - - /* Enhanced Modal Layout */ - .modal-dialog { - margin: 0.75rem; - max-width: calc(100% - 1.5rem); - } - - .modal-content { - border-radius: var(--mobile-border-radius); - border: none; - box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.15); - } - - .modal-header, .modal-body, .modal-footer { - padding: 1.25rem; - } - - .modal-footer { - flex-direction: column; - gap: 0.75rem; - } - - .modal-footer .btn { - width: 100%; - margin-bottom: 0; - } - - /* Enhanced Typography */ - h1 { font-size: 1.875rem; line-height: 1.2; } - h2 { font-size: 1.625rem; line-height: 1.2; } - h3 { font-size: 1.375rem; line-height: 1.3; } - h4 { font-size: 1.125rem; line-height: 1.3; } - h5 { font-size: 1rem; line-height: 1.4; } - h6 { font-size: 0.95rem; line-height: 1.4; } - - /* Enhanced Spacing */ - .mb-4 { margin-bottom: var(--mobile-section-spacing) !important; } - .mb-3 { margin-bottom: var(--mobile-card-spacing) !important; } - .mb-2 { margin-bottom: 0.75rem !important; } - - .py-4 { padding-top: var(--mobile-section-spacing) !important; padding-bottom: var(--mobile-section-spacing) !important; } - .py-3 { padding-top: var(--mobile-card-spacing) !important; padding-bottom: var(--mobile-card-spacing) !important; } - - .px-4 { padding-left: var(--mobile-card-padding) !important; padding-right: var(--mobile-card-padding) !important; } - .px-3 { padding-left: 1rem !important; padding-right: 1rem !important; } - - /* Enhanced Utility Classes */ - .mobile-stack { - display: flex; - flex-direction: column; - gap: 0.75rem; - } - - .mobile-stack .btn { - margin-bottom: 0; - width: 100%; - } - - .touch-target { - min-height: var(--mobile-touch-target); - min-width: var(--mobile-touch-target); - } - - /* Enhanced Mobile Components */ - .mobile-card { - margin-bottom: var(--mobile-card-spacing); - border-radius: var(--mobile-border-radius); - box-shadow: var(--mobile-shadow); - transition: all 0.3s ease; - } - - /* Mobile table action group horizontal layout */ - .table td .btn-group { - display: flex; - flex-direction: row; - flex-wrap: nowrap; - gap: 0.5rem; - width: 100%; - } - .table td .btn-group .btn { - flex: 1 1 auto; - min-width: 0; - padding: 0.875rem 0.75rem; - font-size: 1rem; - } - - .mobile-card:hover { - box-shadow: var(--mobile-shadow-hover); - transform: translateY(-2px); - } - - .mobile-btn { - width: auto; - margin-bottom: 0.75rem; - padding: 1rem 1.5rem; - font-size: 1rem; - min-height: var(--mobile-button-height); - border-radius: var(--mobile-border-radius); - } - - .mobile-btn:last-child { - margin-bottom: 0; - } - - /* Enhanced Mobile Table Layout */ - .mobile-table-row { - background: var(--bs-card-bg, #ffffff); - border: 1px solid var(--border-color); - border-radius: var(--mobile-border-radius); - margin-bottom: var(--mobile-card-spacing); - padding: 1rem; - box-shadow: var(--mobile-shadow); - transition: all 0.3s ease; - } - - .mobile-table-row:hover { - box-shadow: var(--mobile-shadow-hover); - transform: translateY(-1px); - } - - .mobile-table-row .row { - margin: 0; - } - - .mobile-table-row .col { - padding: 0.75rem 0; - border-bottom: 1px solid #f1f5f9; - margin-bottom: 0.5rem; - } - - .mobile-table-row .col:last-child { - border-bottom: none; - margin-bottom: 0; - } - - .mobile-table-row .col:before { - content: attr(data-label) ": "; - font-weight: 600; - color: var(--text-primary); - display: block; - margin-bottom: 0.5rem; - font-size: 0.875rem; - text-transform: uppercase; - letter-spacing: 0.5px; - color: var(--text-muted); - } - - /* Enhanced Mobile Form Layout */ - .mobile-form-group { - margin-bottom: 1.5rem; - } - - .mobile-form-group .form-label { - display: block; - margin-bottom: 0.75rem; - font-weight: 600; - color: var(--text-primary); - } - - .mobile-form-group .form-control, - .mobile-form-group .form-select { - width: 100%; - margin-bottom: 0.5rem; - } - - .mobile-form-group .form-text { - margin-top: 0.25rem; - font-size: 0.8rem; - } - - /* Enhanced Mobile Navigation */ - .mobile-nav-item { - padding: 1rem 1.5rem; - border-radius: var(--mobile-border-radius); - margin: 0.25rem 0; - transition: all 0.3s ease; - min-height: var(--mobile-touch-target); - display: flex; - align-items: center; - gap: 0.75rem; - background: var(--bs-card-bg, #ffffff); - border: 1px solid var(--border-color); - } - - .mobile-nav-item:hover { - background: var(--light-color); - transform: translateX(4px); - box-shadow: var(--mobile-shadow); - } - - .mobile-nav-item.active { - background: #6b7280; - color: white; - border-color: #6b7280; - box-shadow: 0 4px 12px rgba(107, 114, 128, 0.3); - } - - /* Enhanced Mobile Animations */ - .mobile-fade-in { - animation: mobileFadeIn 0.4s ease-out; - } - - .mobile-slide-up { - animation: mobileSlideUp 0.4s ease-out; - } - - @keyframes mobileFadeIn { - from { - opacity: 0; - transform: translateY(20px); - } - to { - opacity: 1; - transform: translateY(0); - } - } - - @keyframes mobileSlideUp { - from { - opacity: 0; - transform: translateY(30px); - } - to { - opacity: 1; - transform: translateY(0); - } - } - - /* Enhanced Mobile Shadows */ - .mobile-shadow { - box-shadow: var(--mobile-shadow); - } - - .mobile-shadow-hover { - box-shadow: var(--mobile-shadow-hover); - } - - /* Enhanced Mobile Borders */ - .mobile-border { - border: 1px solid var(--border-color); - border-radius: var(--mobile-border-radius); - } - - /* Enhanced Mobile Backgrounds */ - .mobile-bg-light { - background-color: #f8fafc; - } - - .mobile-bg-white { - background-color: white; - } - - /* Enhanced Mobile Text Colors */ - .mobile-text-primary { - color: var(--text-primary) !important; - } - - .mobile-text-secondary { - color: #475569 !important; - } - - .mobile-text-muted { - color: var(--text-muted) !important; - } - - /* Enhanced Mobile Spacing Utilities */ - .mobile-p-0 { padding: 0 !important; } - .mobile-p-1 { padding: 0.25rem !important; } - .mobile-p-2 { padding: 0.5rem !important; } - .mobile-p-3 { padding: 1rem !important; } - .mobile-p-4 { padding: 1.25rem !important; } - - .mobile-m-0 { margin: 0 !important; } - .mobile-m-1 { margin: 0.25rem !important; } - .mobile-m-2 { margin: 0.5rem !important; } - .mobile-m-3 { margin: 1rem !important; } - .mobile-m-4 { margin: 1.25rem !important; } - - /* Enhanced Mobile Grid Layout */ - .mobile-grid-2 { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 0.75rem; - } - - .mobile-grid-3 { - display: grid; - grid-template-columns: 1fr 1fr 1fr; - gap: 0.75rem; - } - - @media (max-width: 480px) { - .mobile-grid-2, - .mobile-grid-3 { - grid-template-columns: 1fr; - } - } -} - -/* Enhanced Mobile Navigation */ -.navbar-toggler { - border: none; - padding: 0.5rem; - border-radius: var(--mobile-border-radius); - transition: all 0.3s ease; -} - -.navbar-toggler:focus { - box-shadow: var(--focus-ring, 0 0 0 3px rgba(59, 130, 246, 0.1)); -} - -.navbar-toggler-icon { - background-image: none; - width: 24px; - height: 18px; - position: relative; - transition: all 0.3s ease; -} - -.navbar-toggler-icon::before, -.navbar-toggler-icon::after, -.navbar-toggler-icon { - background: var(--text-primary); -} - -.navbar-toggler-icon::before, -.navbar-toggler-icon::after { - content: ''; - position: absolute; - left: 0; - width: 100%; - height: 2px; - background: var(--text-primary); - transition: all 0.3s ease; -} - -.navbar-toggler-icon::before { - top: -6px; -} - -.navbar-toggler-icon::after { - bottom: -6px; -} - -.navbar-toggler[aria-expanded="true"] .navbar-toggler-icon { - background: transparent; -} - -.navbar-toggler[aria-expanded="true"] .navbar-toggler-icon::before { - transform: rotate(45deg); - top: 0; -} - -.navbar-toggler[aria-expanded="true"] .navbar-toggler-icon::after { - transform: rotate(-45deg); - bottom: 0; -} - -/* Mobile Bottom Tab Bar */ -@media (max-width: 768px) { - .mobile-tabbar { - position: fixed; - left: 0; - right: 0; - bottom: 0; - height: calc(var(--mobile-tabbar-height) + env(safe-area-inset-bottom)); - background: rgba(255, 255, 255, 0.95); - border-top: 1px solid var(--border-light); - box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1); - backdrop-filter: blur(16px); - -webkit-backdrop-filter: blur(16px); - display: flex; - align-items: center; - justify-content: space-around; - padding-bottom: env(safe-area-inset-bottom); - z-index: var(--z-fixed); - transition: all var(--transition); - } - - .mobile-tabbar::before { - content: ''; - position: absolute; - top: 0; - left: 10%; - right: 10%; - height: 1px; - background: linear-gradient(90deg, transparent, var(--primary-color), transparent); - opacity: 0.3; - } - - [data-theme="dark"] .mobile-tabbar { - background: rgba(11, 18, 32, 0.95); - box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.3); - } - .mobile-tabbar .tab-item { - flex: 1 1 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 0.25rem; - height: var(--mobile-tabbar-height); - color: var(--text-tertiary); - text-decoration: none; - font-size: 0.75rem; - font-weight: var(--font-weight-medium); - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - border-radius: 0; - margin: 0 0.125rem; - position: relative; - touch-action: manipulation; - -webkit-tap-highlight-color: transparent; - overflow: hidden; - } - - .mobile-tabbar .tab-item::before { - content: ''; - position: absolute; - top: 50%; - left: 50%; - width: 0; - height: 0; - background: rgba(59, 130, 246, 0.1); - border-radius: 50%; - transform: translate(-50%, -50%); - transition: width 0.3s ease, height 0.3s ease; - z-index: 0; - } - - .mobile-tabbar .tab-item:active::before { - width: 100%; - height: 100%; - } - - .mobile-tabbar .tab-item > * { - position: relative; - z-index: 1; - } - .mobile-tabbar .tab-item .tab-icon { - font-size: 1.25rem; - line-height: 1; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - } - - .mobile-tabbar .tab-item:hover .tab-icon, - .mobile-tabbar .tab-item.active .tab-icon { - transform: scale(1.1); - } - - .mobile-tabbar .tab-item.active .tab-icon { - animation: bounce 0.6s ease; - } - - @keyframes bounce { - 0%, 20%, 53%, 80%, 100% { - transform: scale(1.1); - } - 40%, 43% { - transform: scale(1.2); - } - 70% { - transform: scale(1.15); - } - 90% { - transform: scale(1.05); - } - } - .mobile-tabbar .tab-item:hover, - .mobile-tabbar .tab-item.active { - color: var(--primary-color); - background: var(--primary-50); - transform: translateY(-1px); - } - - .mobile-tabbar .tab-item.active { - background: linear-gradient(135deg, var(--primary-100), var(--primary-50)); - box-shadow: 0 2px 8px rgba(59, 130, 246, 0.2); - } - - .mobile-tabbar .tab-item:active { - transform: scale(0.95); - transition: all 0.15s ease; - background: var(--primary-200); - } - - /* Enhanced touch feedback for tab items */ - @media (hover: none) and (pointer: coarse) { - .mobile-tabbar .tab-item:active { - background: var(--primary-100); - transform: scale(0.92); - } - } -} - -/* Respect forced light theme on mobile if explicitly set */ -@media (prefers-color-scheme: dark) { - /* Respect explicit light theme: variables already ensure light styling */ - html[data-theme="light"] .navbar, - html[data-theme="light"] .mobile-tabbar { - background: var(--navbar-bg) !important; - border-color: var(--border-color) !important; - } -} - -/* Enhanced Small Mobile Devices */ -@media (max-width: 480px) { - .container, .container-fluid { - padding-left: 0.75rem; - padding-right: 0.75rem; - } - - .card-body { - padding: 1rem; - } - - .card-header { - padding: 1rem 1rem; - } - - .btn { - padding: 1rem 1.25rem; - font-size: 0.95rem; - min-height: 56px; - /* inherit visual styles from base button tokens */ - } - - .btn:hover { transform: translateY(-1px); } - - .form-control, .form-select { - padding: 0.875rem 1rem; - min-height: 56px; - } - - .navbar-brand { - font-size: 1.1rem; - } - - .table td { - padding: 0.875rem; - } - - .modal-dialog { - margin: 0.5rem; - max-width: calc(100% - 1rem); - } - - .modal-header, .modal-body, .modal-footer { - padding: 1rem; - } - - /* Enhanced Small Mobile Typography */ - h1 { font-size: 1.75rem; } - h2 { font-size: 1.5rem; } - h3 { font-size: 1.25rem; } - h4 { font-size: 1.125rem; } - h5 { font-size: 1rem; } - h6 { font-size: 0.9rem; } - - /* Enhanced Small Mobile Spacing */ - .mb-4 { margin-bottom: 1.25rem !important; } - .mb-3 { margin-bottom: 1rem !important; } - .mb-2 { margin-bottom: 0.75rem !important; } - - .py-4 { padding-top: 1.25rem !important; padding-bottom: 1.25rem !important; } - .py-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } -} - -/* Enhanced Landscape Mobile Devices */ -@media (max-width: 768px) and (orientation: landscape) { - .navbar-collapse { - max-height: 70vh; - overflow-y: auto; - } - - .modal-dialog { - margin: 1rem; - max-width: calc(100% - 2rem); - } - - .card-body { - padding: 1rem; - } - - .btn { - min-height: 48px; - padding: 0.875rem 1.5rem; - /* inherit visual styles from base button tokens */ - } - - .btn:hover { transform: translateY(-1px); } -} - -/* Enhanced High-DPI Mobile Devices */ -@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { - .btn, .form-control, .form-select { - border-width: 0.5px; - } - - .table td { - border-bottom-width: 0.5px; - } - - .card { - border-width: 0.5px; - } -} - -/* Enhanced Mobile Print Styles */ -@media print and (max-width: 768px) { - .navbar, .btn, .modal, .dropdown { - display: none !important; - } - - .card { - border: 1px solid #000 !important; - box-shadow: none !important; - margin-bottom: 1rem !important; - } - - .table td { - border: 1px solid #000 !important; - } - - .container { - padding: 0 !important; - max-width: 100% !important; - } -} - -/* Enhanced Analytics Dashboard Mobile Styles */ -@media (max-width: 768px) { - .chart-container { - min-height: 250px !important; - margin-bottom: var(--mobile-card-spacing); - } - - .analytics-card { - margin-bottom: var(--mobile-card-spacing); - } - - .analytics-summary-card { - padding: 1rem; - text-align: center; - } - - .analytics-summary-card h6 { - font-size: 1.1rem; - margin-bottom: 0.5rem; - color: var(--text-primary); - } - - .analytics-summary-card small { - font-size: 0.8rem; - color: var(--text-muted); - } - - .analytics-summary-card i { - font-size: 1.5rem !important; - margin-bottom: 0.75rem; - color: #6b7280; - } - - .analytics-chart-wrapper { - background: var(--bs-card-bg, #ffffff); - border-radius: var(--mobile-border-radius); - padding: 1rem; - box-shadow: var(--mobile-shadow); - margin-bottom: var(--mobile-card-spacing); - } -} - -/* Enhanced Chart.js Mobile Optimizations */ -@media (max-width: 768px) { - .chartjs-tooltip { - font-size: 0.875rem !important; - padding: 0.75rem !important; - border-radius: var(--mobile-border-radius); - box-shadow: var(--mobile-shadow-hover); - } - - .chartjs-legend { - font-size: 0.875rem !important; - margin-top: 1rem; - } - - .chartjs-legend-item { - margin-bottom: 0.5rem; - display: flex; - align-items: center; - gap: 0.5rem; - } -} - -/* Enhanced Mobile Loading States */ -@media (max-width: 768px) { - .loading-skeleton { - background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); - background-size: 200% 100%; - animation: loading 1.5s infinite; - border-radius: var(--mobile-border-radius); - height: 20px; - margin-bottom: 0.75rem; - } - - @keyframes loading { - 0% { background-position: 200% 0; } - 100% { background-position: -200% 0; } - } - - .loading-card { - min-height: 200px; - background: var(--light-color); - border-radius: var(--mobile-border-radius); - display: flex; - align-items: center; - justify-content: center; - color: var(--text-muted); - font-size: 0.9rem; - } -} - -/* Enhanced Mobile Dark Mode Support via data-theme */ -@media (max-width: 768px) { - [data-theme="dark"] .navbar { - background: var(--navbar-bg) !important; - border-bottom-color: var(--border-color) !important; - } - [data-theme="dark"] .navbar-collapse { background: var(--navbar-bg); border-color: var(--border-color); } - [data-theme="dark"] .card { background: var(--bs-card-bg); border-color: var(--border-color); color: var(--text-primary); } - [data-theme="dark"] .table td { background: var(--bs-card-bg); color: var(--text-secondary); } - [data-theme="dark"] .form-control, - [data-theme="dark"] .form-select { background: #0f172a; border-color: var(--border-color); color: var(--text-primary); } - [data-theme="dark"] .dropdown-menu { background: var(--dropdown-bg) !important; border-color: var(--border-color); box-shadow: 0 4px 12px rgba(0,0,0,0.3); } - [data-theme="dark"] .dropdown-item { color: var(--text-secondary) !important; } - [data-theme="dark"] .dropdown-item:hover { background: #111827 !important; color: var(--text-primary) !important; } - [data-theme="dark"] .dropdown-divider { border-top-color: var(--border-color) !important; } - [data-theme="dark"] .dropdown-toggle { background: var(--dropdown-bg) !important; border-color: var(--border-color) !important; color: var(--text-secondary) !important; } - [data-theme="dark"] .dropdown-toggle:hover { background: #111827 !important; border-color: var(--border-color) !important; color: var(--text-primary) !important; } -} - diff --git a/app/static/reports.css b/app/static/reports.css deleted file mode 100644 index 21beea7..0000000 --- a/app/static/reports.css +++ /dev/null @@ -1,679 +0,0 @@ -/** - * Reports Enhanced Styling - * Modern, clean styles for the reports section - */ - -/* Report Container */ -.reports-container { - background: var(--body-bg, #ffffff); - min-height: calc(100vh - var(--navbar-height, 72px)); -} - -/* Summary Cards - Enhanced */ -.summary-card { - border: 1px solid var(--border-light, #f1f5f9) !important; - background: var(--card-bg, #ffffff); - cursor: default; -} - -.summary-icon { - width: 56px; - height: 56px; - border-radius: var(--border-radius-lg, 12px); - display: flex; - align-items: center; - justify-content: center; - font-size: 1.5rem; -} - -.summary-label { - font-size: 0.875rem; - font-weight: 500; - color: var(--text-secondary, #475569); - text-transform: uppercase; - letter-spacing: 0.5px; - margin-bottom: 0.25rem; -} - -.summary-value { - font-size: 2rem; - font-weight: 700; - color: var(--text-primary, #1e293b); - line-height: 1.2; -} - -.summary-trend { - font-size: 0.75rem; - font-weight: 600; - margin-top: 0.5rem; -} - -.summary-trend.up { - color: var(--success-color, #10b981); -} - -.summary-trend.down { - color: var(--danger-color, #ef4444); -} - -/* Filter Section */ -.filters-card { - background: var(--surface-variant, #f8fafc); - border: 1px solid var(--border-color, #e2e8f0) !important; -} - -.filters-card .card-header { - background: var(--card-bg, #ffffff); - border-bottom: 1px solid var(--border-color, #e2e8f0); -} - -.date-presets-container { - margin-bottom: 1rem; - padding: 1rem; - background: var(--card-bg, #ffffff); - border-radius: var(--border-radius, 8px); - border: 1px dashed var(--border-color, #e2e8f0); -} - -.date-presets-label { - font-size: 0.875rem; - font-weight: 600; - color: var(--text-secondary, #475569); - margin-bottom: 0.75rem; - display: block; -} - -#datePresets .btn-group { - gap: 0.5rem; -} - -#datePresets .btn { - font-size: 0.8125rem; - padding: 0.375rem 0.875rem; - border-radius: var(--border-radius-sm, 6px); - font-weight: 500; - transition: all 0.2s ease; -} - -#datePresets .btn:hover { - transform: translateY(-2px); - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); -} - -/* Report Tables */ -.report-table { - border-collapse: separate; - border-spacing: 0; -} - -.report-table thead th { - background: var(--gray-50, #f9fafb); - color: var(--text-secondary, #475569); - font-weight: 600; - font-size: 0.8125rem; - text-transform: uppercase; - letter-spacing: 0.5px; - padding: 1rem 1.25rem; - border-bottom: 2px solid var(--border-color, #e2e8f0); - white-space: nowrap; -} - -.report-table thead th[data-sortable] { - cursor: pointer; - user-select: none; -} - -.report-table thead th[data-sortable]:hover { - background: var(--gray-100, #f3f4f6); - color: var(--primary-color, #3b82f6); -} - -.report-table thead th.sort-asc, -.report-table thead th.sort-desc { - background: var(--primary-50, #eff6ff); - color: var(--primary-color, #3b82f6); -} - -.report-table tbody tr { - transition: all 0.2s ease; - border-bottom: 1px solid var(--border-light, #f1f5f9); -} - -.report-table tbody tr:hover { - background: var(--surface-hover, #f8fafc); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); -} - -.report-table tbody td { - padding: 1rem 1.25rem; - vertical-align: middle; - font-size: 0.9375rem; - color: var(--text-primary, #1e293b); -} - -.report-table tbody td strong { - font-weight: 600; - color: var(--text-primary, #1e293b); -} - -/* Table Actions */ -.table-actions { - display: flex; - gap: 0.5rem; - justify-content: flex-end; -} - -.btn-action { - padding: 0.375rem 0.75rem; - font-size: 0.875rem; - border-radius: var(--border-radius-sm, 6px); - transition: all 0.2s ease; -} - -.btn-action:hover { - transform: translateY(-2px); - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); -} - -.btn-action--view { - background: var(--primary-50, #eff6ff); - color: var(--primary-color, #3b82f6); - border: 1px solid var(--primary-200, #bfdbfe); -} - -.btn-action--view:hover { - background: var(--primary-color, #3b82f6); - color: white; -} - -.btn-action--more { - background: var(--gray-50, #f9fafb); - color: var(--text-secondary, #475569); - border: 1px solid var(--border-color, #e2e8f0); -} - -.btn-action--more:hover { - background: var(--gray-100, #f3f4f6); - color: var(--text-primary, #1e293b); -} - -/* Chart Containers */ -.chart-container { - position: relative; - height: 350px; - margin: 1.5rem 0; - padding: 1.5rem; - background: var(--card-bg, #ffffff); - border-radius: var(--border-radius, 8px); - border: 1px solid var(--border-light, #f1f5f9); -} - -.chart-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 1.5rem; -} - -.chart-title { - font-size: 1.125rem; - font-weight: 600; - color: var(--text-primary, #1e293b); - margin: 0; -} - -.chart-controls { - display: flex; - gap: 0.5rem; -} - -.chart-toggle-btn { - padding: 0.375rem 0.75rem; - font-size: 0.875rem; - border: 1px solid var(--border-color, #e2e8f0); - background: var(--card-bg, #ffffff); - color: var(--text-secondary, #475569); - border-radius: var(--border-radius-sm, 6px); - cursor: pointer; - transition: all 0.2s ease; -} - -.chart-toggle-btn:hover, -.chart-toggle-btn.active { - background: var(--primary-color, #3b82f6); - color: white; - border-color: var(--primary-color, #3b82f6); -} - -/* Empty State */ -.empty-state { - padding: 3rem 2rem; - text-align: center; -} - -.empty-state i { - font-size: 4rem; - color: var(--gray-300, #d1d5db); - margin-bottom: 1.5rem; -} - -.empty-state h5 { - font-size: 1.25rem; - font-weight: 600; - color: var(--text-secondary, #475569); - margin-bottom: 0.75rem; -} - -.empty-state p { - font-size: 0.9375rem; - color: var(--text-tertiary, #64748b); - max-width: 400px; - margin: 0 auto; -} - -/* Pagination Controls */ -.pagination-controls { - border-top: 1px solid var(--border-light, #f1f5f9); - padding-top: 1rem; -} - -.pagination-info { - font-size: 0.875rem; - color: var(--text-secondary, #475569); -} - -.pagination .page-link { - color: var(--text-secondary, #475569); - border: 1px solid var(--border-color, #e2e8f0); - padding: 0.375rem 0.75rem; - font-size: 0.875rem; - border-radius: var(--border-radius-sm, 6px); - margin: 0 0.25rem; -} - -.pagination .page-link:hover { - background: var(--primary-50, #eff6ff); - color: var(--primary-color, #3b82f6); - border-color: var(--primary-200, #bfdbfe); -} - -.pagination .page-item.active .page-link { - background: var(--primary-color, #3b82f6); - border-color: var(--primary-color, #3b82f6); - color: white; -} - -.pagination .page-item.disabled .page-link { - opacity: 0.5; - cursor: not-allowed; -} - -/* Report Export Options */ -.export-options { - display: flex; - gap: 0.75rem; - flex-wrap: wrap; -} - -.export-btn { - display: inline-flex; - align-items: center; - gap: 0.5rem; - padding: 0.625rem 1.25rem; - font-size: 0.9375rem; - font-weight: 500; - border-radius: var(--border-radius, 8px); - transition: all 0.2s ease; -} - -.export-btn i { - font-size: 1rem; -} - -.export-btn:hover { - transform: translateY(-2px); - box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15); -} - -/* Progress Bars */ -.progress-compact { - height: 8px; - border-radius: var(--border-radius-full, 9999px); - background: var(--gray-100, #f3f4f6); - overflow: hidden; -} - -.progress-compact .progress-bar { - border-radius: var(--border-radius-full, 9999px); - transition: width 0.6s ease; -} - -/* Report Stats Grid */ -.report-stats-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: 1rem; - margin-bottom: 2rem; -} - -.report-stat-item { - padding: 1.25rem; - background: var(--card-bg, #ffffff); - border: 1px solid var(--border-light, #f1f5f9); - border-radius: var(--border-radius, 8px); - cursor: default; -} - -.report-stat-label { - font-size: 0.8125rem; - font-weight: 500; - color: var(--text-secondary, #475569); - text-transform: uppercase; - letter-spacing: 0.5px; - margin-bottom: 0.5rem; -} - -.report-stat-value { - font-size: 1.75rem; - font-weight: 700; - color: var(--text-primary, #1e293b); -} - -/* Hover Card Effects */ -.hover-lift { - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); -} - -.hover-lift:hover { - transform: translateY(-4px); - box-shadow: 0 12px 24px -8px rgba(0, 0, 0, 0.15) !important; -} - -/* Print Styles */ -@media print { - .filters-card, - .export-options, - .btn-action, - .pagination-controls, - .no-print { - display: none !important; - } - - .summary-card { - break-inside: avoid; - } - - .report-table { - font-size: 0.875rem; - } - - .chart-container { - break-inside: avoid; - } -} - -/* Responsive Design */ -@media (max-width: 768px) { - .summary-value { - font-size: 1.5rem; - } - - .summary-icon { - width: 48px; - height: 48px; - font-size: 1.25rem; - } - - .chart-container { - height: 280px; - padding: 1rem; - } - - .report-table thead th, - .report-table tbody td { - padding: 0.75rem; - font-size: 0.875rem; - } - - #datePresets .btn-group { - flex-direction: column; - width: 100%; - } - - #datePresets .btn { - width: 100%; - text-align: left; - } - - .export-options { - flex-direction: column; - } - - .export-btn { - width: 100%; - justify-content: center; - } - - .report-stats-grid { - grid-template-columns: 1fr; - } -} - -/* Loading State */ -.report-loading { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 4rem 2rem; - color: var(--text-secondary, #475569); -} - -.report-loading .spinner-border { - width: 3rem; - height: 3rem; - border-width: 0.3rem; - margin-bottom: 1.5rem; -} - -.report-loading-text { - font-size: 1rem; - font-weight: 500; -} - -/* Badges and Tags */ -.report-badge { - display: inline-flex; - align-items: center; - padding: 0.25rem 0.75rem; - font-size: 0.8125rem; - font-weight: 600; - border-radius: var(--border-radius-full, 9999px); - white-space: nowrap; -} - -.report-badge.badge-billable { - background: var(--success-light, #d1fae5); - color: var(--success-color, #10b981); -} - -.report-badge.badge-non-billable { - background: var(--gray-100, #f3f4f6); - color: var(--text-tertiary, #64748b); -} - -/* Table Search */ -.table-search-container { - margin-bottom: 1rem; -} - -.table-search { - width: 100%; - max-width: 400px; - padding: 0.625rem 1rem; - border: 1px solid var(--border-color, #e2e8f0); - border-radius: var(--border-radius, 8px); - font-size: 0.9375rem; - transition: all 0.2s ease; -} - -.table-search:focus { - outline: none; - border-color: var(--primary-color, #3b82f6); - box-shadow: var(--focus-ring, 0 0 0 3px rgba(59, 130, 246, 0.12)); -} - -/* Comparison View */ -.comparison-view { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); - gap: 1.5rem; - margin-bottom: 2rem; -} - -.comparison-card { - padding: 1.5rem; - background: var(--card-bg, #ffffff); - border: 2px solid var(--border-light, #f1f5f9); - border-radius: var(--border-radius-lg, 12px); - cursor: default; -} - -.comparison-header { - font-size: 1.125rem; - font-weight: 600; - color: var(--text-primary, #1e293b); - margin-bottom: 1rem; - padding-bottom: 0.75rem; - border-bottom: 2px solid var(--border-light, #f1f5f9); -} - -.comparison-metric { - display: flex; - justify-content: space-between; - align-items: center; - padding: 0.75rem 0; -} - -.comparison-metric-label { - font-size: 0.9375rem; - color: var(--text-secondary, #475569); -} - -.comparison-metric-value { - font-size: 1.125rem; - font-weight: 600; - color: var(--text-primary, #1e293b); -} - -/* Reports Grid - Clean Compact Layout */ -.reports-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); - gap: 0.75rem; -} - -.report-item { - display: flex; - align-items: center; - padding: 1rem; - background: var(--card-bg, #ffffff); - border: 1px solid var(--border-light, #f1f5f9); - border-radius: var(--border-radius, 8px); - text-decoration: none; - color: inherit; - transition: all 0.2s ease; - cursor: pointer; -} - -.report-item:hover { - background: var(--surface-hover, #f8fafc); - border-color: var(--primary-color, #3b82f6); - box-shadow: 0 2px 8px rgba(59, 130, 246, 0.1); - transform: translateX(4px); -} - -.report-item-icon { - flex-shrink: 0; - width: 44px; - height: 44px; - border-radius: var(--border-radius, 8px); - display: flex; - align-items: center; - justify-content: center; - font-size: 1.25rem; - margin-right: 1rem; -} - -.report-item-content { - flex-grow: 1; - min-width: 0; -} - -.report-item-title { - font-size: 0.9375rem; - font-weight: 600; - color: var(--text-primary, #1e293b); - margin: 0 0 0.25rem 0; - line-height: 1.3; -} - -.report-item-description { - font-size: 0.8125rem; - color: var(--text-secondary, #64748b); - margin: 0; - line-height: 1.4; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.report-item-arrow { - flex-shrink: 0; - color: var(--text-muted, #9ca3af); - font-size: 0.875rem; - margin-left: 0.75rem; - transition: all 0.2s ease; -} - -.report-item:hover .report-item-arrow { - color: var(--primary-color, #3b82f6); - transform: translateX(2px); -} - -/* Purple color utility for analytics */ -.bg-purple { - background-color: #8b5cf6 !important; -} - -.text-purple { - color: #8b5cf6 !important; -} - -/* Responsive adjustments for report grid */ -@media (max-width: 768px) { - .reports-grid { - grid-template-columns: 1fr; - gap: 0.5rem; - } - - .report-item { - padding: 0.875rem; - } - - .report-item-icon { - width: 40px; - height: 40px; - font-size: 1.125rem; - margin-right: 0.875rem; - } - - .report-item-title { - font-size: 0.875rem; - } - - .report-item-description { - font-size: 0.75rem; - } -} - diff --git a/app/static/src/input.css b/app/static/src/input.css new file mode 100644 index 0000000..9b8012c --- /dev/null +++ b/app/static/src/input.css @@ -0,0 +1,34 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer components { + .form-input { + @apply mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-800 dark:border-gray-600 px-4 py-3; + } +} + +.cmdk-root { + --cmdk-font-family: 'Inter', sans-serif; + --cmdk-background: #fff; + --cmdk-border-radius: 8px; + --cmdk-box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + --cmdk-color-text: #333; + --cmdk-color-placeholder: #999; + --cmdk-color-input: #333; + --cmdk-color-separator: #ddd; + --cmdk-color-item-hover: #f5f5f5; + --cmdk-color-item-active: #eee; + --cmdk-height: 400px; + --cmdk-padding: 12px; +} + +[cmdk-theme='dark'] .cmdk-root { + --cmdk-background: #1A202C; /* background-dark */ + --cmdk-color-text: #E2E8F0; /* text-dark */ + --cmdk-color-placeholder: #718096; /* text-muted-dark */ + --cmdk-color-input: #E2E8F0; + --cmdk-color-separator: #4A5568; /* border-dark */ + --cmdk-color-item-hover: #2D3748; /* card-dark */ + --cmdk-color-item-active: #4A5568; +} diff --git a/app/static/theme-template.css b/app/static/theme-template.css deleted file mode 100644 index 62d1c83..0000000 --- a/app/static/theme-template.css +++ /dev/null @@ -1,504 +0,0 @@ -/* TimeTracker Modern Theme Template - Enhanced CSS Variables */ -/* This file contains the complete modern theme system used in TimeTracker */ -/* It can be used as a template for future customizations while maintaining consistency */ - -/* ===== MODERN LIGHT THEME VARIABLES ===== */ -:root { - /* Primary Color Palette - Enhanced Modern Blue */ - --primary-color: #3b82f6; /* Main brand color - Modern Blue */ - --primary-dark: #2563eb; /* Darker shade for hover states */ - --primary-light: #93c5fd; /* Lighter shade for subtle accents */ - --primary-50: #eff6ff; /* Ultra light blue */ - --primary-100: #dbeafe; /* Very light blue */ - --primary-200: #bfdbfe; /* Light blue */ - --primary-300: #93c5fd; /* Medium light blue */ - --primary-400: #60a5fa; /* Medium blue */ - --primary-500: #3b82f6; /* Base blue */ - --primary-600: #2563eb; /* Medium dark blue */ - --primary-700: #1d4ed8; /* Dark blue */ - --primary-800: #1e40af; /* Very dark blue */ - --primary-900: #1e3a8a; /* Ultra dark blue */ - - /* Semantic Color System */ - --secondary-color: #64748b; /* Neutral gray for secondary elements */ - --success-color: #10b981; /* Enhanced green for success states */ - --success-light: #d1fae5; /* Light success background */ - --danger-color: #ef4444; /* Enhanced red for error/danger states */ - --danger-light: #fee2e2; /* Light danger background */ - --warning-color: #f59e0b; /* Enhanced orange for warning states */ - --warning-light: #fef3c7; /* Light warning background */ - --info-color: #06b6d4; /* Enhanced cyan for informational states */ - --info-light: #cffafe; /* Light info background */ - - /* Neutral Color Palette - Enhanced */ - --gray-50: #f9fafb; /* Ultra light gray */ - --gray-100: #f3f4f6; /* Very light gray */ - --gray-200: #e5e7eb; /* Light gray */ - --gray-300: #d1d5db; /* Medium light gray */ - --gray-400: #9ca3af; /* Medium gray */ - --gray-500: #6b7280; /* Base gray */ - --gray-600: #4b5563; /* Medium dark gray */ - --gray-700: #374151; /* Dark gray */ - --gray-800: #1f2937; /* Very dark gray */ - --gray-900: #111827; /* Ultra dark gray */ - - /* Background Colors - Modern Hierarchy */ - --dark-color: #1e293b; /* Dark backgrounds */ - --light-color: #f8fafc; /* Light backgrounds */ - --body-bg: #ffffff; /* Main body background */ - --surface-color: #ffffff; /* Surface backgrounds */ - --surface-variant: #f8fafc; /* Variant surface backgrounds */ - --surface-hover: #f1f5f9; /* Hover surface backgrounds */ - --surface-pressed: #e2e8f0; /* Pressed surface backgrounds */ - - /* Border and Divider Colors - Refined */ - --border-color: #e2e8f0; /* Standard borders */ - --border-light: #f1f5f9; /* Light borders */ - --border-strong: #cbd5e1; /* Strong borders */ - --divider-color: #e2e8f0; /* Divider lines */ - - /* Text Colors - Improved Hierarchy */ - --text-primary: #1e293b; /* Primary text color */ - --text-secondary: #475569; /* Secondary text color */ - --text-tertiary: #64748b; /* Tertiary text color */ - --text-muted: #9ca3af; /* Muted text color */ - --text-on-primary: #ffffff; /* Text on primary backgrounds */ - --text-on-dark: #f8fafc; /* Text on dark backgrounds */ - - /* Component Backgrounds - Enhanced */ - --navbar-bg: rgba(255, 255, 255, 0.95); /* Glass navigation bar */ - --navbar-border: rgba(226, 232, 240, 0.6); /* Navigation border */ - --dropdown-bg: #ffffff; /* Dropdown menu background */ - --card-bg: #ffffff; /* Card background */ - --input-bg: #ffffff; /* Input background */ - --input-border: #d1d5db; /* Input border */ - --input-focus: #3b82f6; /* Input focus color */ - - /* Visual Effects - Modern Shadows and Gradients */ - --bg-gradient: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%); - --bg-gradient-subtle: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%); - --card-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1); - --card-shadow-hover: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1); - --card-shadow-lg: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1); - --card-shadow-xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25); - --focus-ring: 0 0 0 3px rgba(59, 130, 246, 0.12); - --focus-ring-danger: 0 0 0 3px rgba(239, 68, 68, 0.12); - --focus-ring-success: 0 0 0 3px rgba(16, 185, 129, 0.12); - - /* Spacing and Layout - Refined System */ - --border-radius: 8px; /* Standard border radius */ - --border-radius-lg: 12px; /* Large border radius */ - --border-radius-sm: 6px; /* Small border radius */ - --border-radius-xs: 4px; /* Extra small border radius */ - --border-radius-full: 9999px; /* Full border radius (circular) */ - --section-spacing: 2.5rem; /* Section spacing */ - --card-spacing: 1.5rem; /* Card spacing */ - --mobile-section-spacing: 1.5rem; /* Mobile section spacing */ - --mobile-card-spacing: 1rem; /* Mobile card spacing */ - --navbar-height: 72px; /* Navigation bar height */ - --container-padding: 1.5rem; /* Container padding */ - --grid-gap: 1.5rem; /* Grid gap */ - --grid-gap-sm: 1rem; /* Small grid gap */ - - /* Transitions and Animations - Enhanced */ - --transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); - --transition-fast: all 0.15s cubic-bezier(0.4, 0, 0.2, 1); - --transition-slow: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - --transition-bounce: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55); - --animation-duration: 0.3s; - --animation-timing: cubic-bezier(0.4, 0, 0.2, 1); - - /* Typography - Enhanced Scale */ - --font-family-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; - --font-family-mono: 'SF Mono', Monaco, Inconsolata, 'Roboto Mono', 'Source Code Pro', monospace; - --font-weight-light: 300; - --font-weight-normal: 400; - --font-weight-medium: 500; - --font-weight-semibold: 600; - --font-weight-bold: 700; - --font-weight-extrabold: 800; - --line-height-tight: 1.25; - --line-height-normal: 1.5; - --line-height-relaxed: 1.625; - - /* Interactive States */ - --hover-opacity: 0.9; - --active-opacity: 0.95; - --disabled-opacity: 0.5; - --loading-opacity: 0.6; - - /* Z-Index Scale */ - --z-dropdown: 1000; - --z-sticky: 1020; - --z-fixed: 1030; - --z-modal-backdrop: 1040; - --z-modal: 1050; - --z-popover: 1060; - --z-tooltip: 1070; - --z-toast: 1080; - - /* Bootstrap Integration - Enhanced */ - --bs-body-bg: var(--body-bg); - --bs-body-color: var(--text-primary); - --bs-body-font-family: var(--font-family-sans); - --bs-body-font-size: 0.95rem; - --bs-body-line-height: var(--line-height-normal); - --bs-card-bg: var(--card-bg); - --bs-card-border-color: var(--border-color); - --bs-card-border-radius: var(--border-radius); - --bs-dropdown-bg: var(--dropdown-bg); - --bs-dropdown-border-color: var(--border-color); - --bs-dropdown-link-color: var(--text-secondary); - --bs-dropdown-link-hover-bg: var(--surface-hover); - --bs-dropdown-link-hover-color: var(--text-primary); -} - -/* ===== MODERN DARK THEME VARIABLES ===== */ -[data-theme="dark"] { - /* Primary Color Palette - Enhanced for dark theme */ - --primary-color: #60a5fa; /* Lighter blue for better contrast */ - --primary-dark: #3b82f6; /* Standard blue for hover */ - --primary-light: #93c5fd; /* Light blue accent */ - --primary-50: #1e3a8a; /* Dark blue (reversed) */ - --primary-100: #1e40af; /* Very dark blue */ - --primary-200: #1d4ed8; /* Dark blue */ - --primary-300: #2563eb; /* Medium dark blue */ - --primary-400: #3b82f6; /* Medium blue */ - --primary-500: #60a5fa; /* Base blue (lighter for dark) */ - --primary-600: #93c5fd; /* Medium light blue */ - --primary-700: #bfdbfe; /* Light blue */ - --primary-800: #dbeafe; /* Very light blue */ - --primary-900: #eff6ff; /* Ultra light blue */ - - /* Semantic Color System - Dark theme */ - --secondary-color: #94a3b8; /* Lighter gray for visibility */ - --success-color: #34d399; /* Brighter green for dark theme */ - --success-light: #064e3b; /* Dark success background */ - --danger-color: #f87171; /* Brighter red for dark theme */ - --danger-light: #7f1d1d; /* Dark danger background */ - --warning-color: #fbbf24; /* Brighter orange for dark theme */ - --warning-light: #78350f; /* Dark warning background */ - --info-color: #38bdf8; /* Brighter cyan for dark theme */ - --info-light: #164e63; /* Dark info background */ - - /* Neutral Color Palette - Dark theme (reversed) */ - --gray-50: #0f172a; /* Dark gray (reversed) */ - --gray-100: #1e293b; /* Very dark gray */ - --gray-200: #334155; /* Dark gray */ - --gray-300: #475569; /* Medium dark gray */ - --gray-400: #64748b; /* Medium gray */ - --gray-500: #94a3b8; /* Base gray (lighter for dark) */ - --gray-600: #cbd5e1; /* Medium light gray */ - --gray-700: #e2e8f0; /* Light gray */ - --gray-800: #f1f5f9; /* Very light gray */ - --gray-900: #f8fafc; /* Ultra light gray */ - - /* Background Colors - Dark theme specific */ - --dark-color: #0f172a; /* Very dark blue-gray */ - --light-color: #1e293b; /* Dark blue-gray */ - --body-bg: #0b1220; /* Main dark background */ - --surface-color: #0f172a; /* Surface backgrounds */ - --surface-variant: #1e293b; /* Variant surface backgrounds */ - --surface-hover: #334155; /* Hover surface backgrounds */ - --surface-pressed: #475569; /* Pressed surface backgrounds */ - - /* Border and Divider Colors - Dark theme */ - --border-color: #334155; /* Dark borders with better contrast */ - --border-light: #1e293b; /* Light borders for dark theme */ - --border-strong: #475569; /* Strong borders for dark theme */ - --divider-color: #334155; /* Divider lines */ - - /* Text Colors - Dark theme */ - --text-primary: #f1f5f9; /* Light gray for primary text */ - --text-secondary: #cbd5e1; /* Medium gray for secondary text */ - --text-tertiary: #94a3b8; /* Tertiary text color */ - --text-muted: #64748b; /* Muted gray for less important text */ - --text-on-primary: #ffffff; /* Text on primary backgrounds */ - --text-on-dark: #0f172a; /* Text on light backgrounds in dark theme */ - - /* Component Backgrounds - Dark theme */ - --navbar-bg: rgba(11, 18, 32, 0.95); /* Glass navigation bar for dark */ - --navbar-border: rgba(51, 65, 85, 0.6); /* Navigation border for dark */ - --dropdown-bg: #0f172a; /* Dark dropdown */ - --card-bg: #0f172a; /* Dark cards */ - --input-bg: #1e293b; /* Input background for dark */ - --input-border: #475569; /* Input border for dark */ - --input-focus: #60a5fa; /* Input focus color for dark */ - - /* Visual Effects - Dark theme */ - --bg-gradient: linear-gradient(135deg, #1e3a8a 0%, #1d4ed8 100%); - --bg-gradient-subtle: linear-gradient(135deg, #1e293b 0%, #334155 100%); - --card-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px -1px rgba(0, 0, 0, 0.4); - --card-shadow-hover: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -4px rgba(0, 0, 0, 0.4); - --card-shadow-lg: 0 20px 25px -5px rgba(0, 0, 0, 0.4), 0 8px 10px -6px rgba(0, 0, 0, 0.4); - --card-shadow-xl: 0 25px 50px -12px rgba(0, 0, 0, 0.6); - --focus-ring: 0 0 0 3px rgba(96, 165, 250, 0.2); - --focus-ring-danger: 0 0 0 3px rgba(248, 113, 113, 0.2); - --focus-ring-success: 0 0 0 3px rgba(52, 211, 153, 0.2); - - /* Bootstrap Integration - Dark theme */ - --bs-body-bg: var(--body-bg); - --bs-body-color: var(--text-primary); - --bs-body-font-family: var(--font-family-sans); - --bs-card-bg: var(--card-bg); - --bs-card-border-color: var(--border-color); - --bs-dropdown-bg: var(--dropdown-bg); - --bs-dropdown-border-color: var(--border-color); - --bs-dropdown-link-color: var(--text-secondary); - --bs-dropdown-link-hover-bg: var(--surface-hover); - --bs-dropdown-link-hover-color: var(--text-primary); -} - -/* ===== MOBILE-SPECIFIC VARIABLES ===== */ -:root { - /* Mobile Touch Targets and Spacing */ - --mobile-touch-target: 52px; /* Minimum touch target size */ - --mobile-nav-height: 70px; /* Mobile navigation height */ - --mobile-tabbar-height: 64px; /* Bottom tab bar height */ - --mobile-card-padding: 1.25rem; /* Mobile card padding */ - --mobile-button-height: 52px; /* Mobile button height */ - --mobile-input-height: 56px; /* Mobile input height */ - --mobile-border-radius: 4px; /* Mobile border radius */ - --mobile-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - --mobile-shadow-hover: 0 4px 16px rgba(0, 0, 0, 0.15); -} - -/* ===== ENHANCED USAGE EXAMPLES ===== */ - -/* Example 1: Modern Themed Card with Glass Effect */ -/* -.modern-card { - background: var(--card-bg); - border: 1px solid var(--border-color); - border-radius: var(--border-radius); - box-shadow: var(--card-shadow); - color: var(--text-primary); - transition: var(--transition-slow); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); - position: relative; - overflow: hidden; -} - -.modern-card::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 2px; - background: linear-gradient(90deg, transparent, var(--primary-color), transparent); - opacity: 0; - transition: opacity var(--transition); -} - -.modern-card:hover { - box-shadow: var(--card-shadow-hover); - transform: translateY(-4px) scale(1.02); - border-color: var(--primary-200); -} - -.modern-card:hover::before { - opacity: 0.8; -} -*/ - -/* Example 2: Enhanced Primary Button with Gradient */ -/* -.btn-modern-primary { - background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-600) 100%); - border: 1px solid var(--primary-color); - color: var(--text-on-primary); - border-radius: var(--border-radius); - padding: 0.875rem 1.5rem; - font-weight: var(--font-weight-medium); - transition: var(--transition-slow); - position: relative; - overflow: hidden; - box-shadow: 0 2px 4px rgba(59, 130, 246, 0.2); -} - -.btn-modern-primary::before { - content: ''; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); - transition: left 0.5s; -} - -.btn-modern-primary:hover::before { - left: 100%; -} - -.btn-modern-primary:hover { - background: linear-gradient(135deg, var(--primary-600) 0%, var(--primary-700) 100%); - transform: translateY(-2px); - box-shadow: 0 8px 25px rgba(59, 130, 246, 0.3); -} -*/ - -/* Example 3: Modern Status Badge System */ -/* -.status-badge { - display: inline-flex; - align-items: center; - gap: 0.375rem; - padding: 0.5rem 0.875rem; - border-radius: var(--border-radius-full); - font-size: 0.8rem; - font-weight: var(--font-weight-medium); - letter-spacing: 0.025em; - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); -} - -.status-badge--success { - background: rgba(16, 185, 129, 0.1); - color: var(--success-color); - border: 1px solid rgba(16, 185, 129, 0.2); -} - -.status-badge--warning { - background: rgba(245, 158, 11, 0.1); - color: var(--warning-color); - border: 1px solid rgba(245, 158, 11, 0.2); -} - -.status-badge--danger { - background: rgba(239, 68, 68, 0.1); - color: var(--danger-color); - border: 1px solid rgba(239, 68, 68, 0.2); -} -*/ - -/* Example 4: Responsive Grid with Modern Spacing */ -/* -.modern-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); - gap: var(--grid-gap); - margin-bottom: var(--section-spacing); -} - -@media (max-width: 768px) { - .modern-grid { - grid-template-columns: 1fr; - gap: var(--grid-gap-sm); - margin-bottom: var(--mobile-section-spacing); - } -} -*/ - -/* Example 5: Modern Form Styling */ -/* -.modern-form-group { - margin-bottom: 1.5rem; -} - -.modern-form-label { - display: block; - font-weight: var(--font-weight-medium); - color: var(--text-primary); - margin-bottom: 0.5rem; - font-size: 0.95rem; -} - -.modern-form-control { - width: 100%; - padding: 0.875rem 1rem; - border: 2px solid var(--input-border); - border-radius: var(--border-radius); - background: var(--input-bg); - color: var(--text-primary); - font-size: 0.95rem; - transition: var(--transition); - font-family: var(--font-family-sans); -} - -.modern-form-control:focus { - outline: none; - border-color: var(--input-focus); - box-shadow: var(--focus-ring); - transform: translateY(-1px); -} -*/ - -/* ===== COMPREHENSIVE THEME CUSTOMIZATION GUIDE ===== */ -/* -MODERN TIMETRACKER THEME CUSTOMIZATION GUIDE -============================================ - -1. COLOR SYSTEM CUSTOMIZATION: - - Primary colors: Modify --primary-* variables for brand colors - - Semantic colors: Adjust --success-*, --danger-*, --warning-*, --info-* for status colors - - Neutral palette: Update --gray-* variables for consistent grayscale - - Always maintain both light and dark theme variants - -2. SPACING SYSTEM: - - Layout spacing: --section-spacing, --card-spacing for consistent layouts - - Component spacing: --grid-gap, --container-padding for internal spacing - - Mobile spacing: --mobile-* variables for responsive design - - Border radius: --border-radius-* for consistent corner styles - -3. TYPOGRAPHY SYSTEM: - - Font families: --font-family-sans, --font-family-mono - - Font weights: --font-weight-* for consistent typography hierarchy - - Line heights: --line-height-* for optimal readability - -4. VISUAL EFFECTS: - - Shadows: --card-shadow-* for depth and elevation - - Gradients: --bg-gradient-* for modern visual appeal - - Focus rings: --focus-ring-* for accessibility - - Transitions: --transition-* for smooth interactions - -5. COMPONENT CUSTOMIZATION: - - Navigation: --navbar-* variables for header styling - - Cards: --card-* variables for content containers - - Forms: --input-* variables for form elements - - Interactive states: --hover-*, --active-* for user feedback - -6. MOBILE OPTIMIZATION: - - Touch targets: --mobile-touch-target for accessibility - - Responsive spacing: --mobile-* variables for smaller screens - - Navigation: --mobile-nav-height, --mobile-tabbar-height - -7. ACCESSIBILITY CONSIDERATIONS: - - Maintain WCAG contrast ratios (4.5:1 for normal text, 3:1 for large text) - - Ensure focus indicators are visible and consistent - - Test with screen readers and keyboard navigation - - Verify color-blind friendly combinations - -8. DARK THEME BEST PRACTICES: - - Increase contrast for better readability - - Use appropriate shadow intensities - - Ensure interactive elements remain discoverable - - Test in various lighting conditions - -9. CUSTOMIZATION WORKFLOW: - - Start with color palette modifications - - Test in both light and dark themes - - Verify mobile responsiveness - - Check accessibility compliance - - Document any custom additions - -10. INTEGRATION WITH BOOTSTRAP: - - Use --bs-* variables for Bootstrap integration - - Override Bootstrap defaults through CSS variables - - Maintain consistency with custom components - -EXAMPLE CUSTOM COLOR SCHEME: ---------------------------- -For a green-themed variant, replace blue primary colors: ---primary-color: #10b981; ---primary-dark: #059669; ---primary-light: #6ee7b7; - -And adjust the full color scale accordingly in both themes. - -Remember to test all changes thoroughly across different devices, -browsers, and accessibility tools before deployment. -*/ diff --git a/app/static/toast-notifications.css b/app/static/toast-notifications.css index 0960574..42a8cba 100644 --- a/app/static/toast-notifications.css +++ b/app/static/toast-notifications.css @@ -1,317 +1,107 @@ -/* Toast Notification System - Professional Design */ +/* Toast Notifications - styled to match TimeTracker UI (light + dark) */ -/* Container for all toasts - positioned at bottom-right */ #toast-notification-container { - position: fixed; - bottom: 24px; - right: 24px; - z-index: 10000; - display: flex; - flex-direction: column-reverse; - gap: 12px; - max-width: 420px; - pointer-events: none; + position: fixed; + top: 1rem; + right: 1rem; + display: flex; + flex-direction: column; + gap: 0.5rem; + z-index: 9999; + pointer-events: none; /* clicks pass through except inside toasts */ } -/* Mobile adjustments */ -@media (max-width: 576px) { - #toast-notification-container { - bottom: 80px; /* Above mobile tab bar */ - right: 16px; - left: 16px; - max-width: none; - } +@media (max-width: 640px) { + #toast-notification-container { + top: auto; + right: 0.75rem; + left: 0.75rem; + bottom: 0.75rem; + } } -/* Individual toast notification */ .toast-notification { - pointer-events: all; - background: white; - border-radius: 12px; - box-shadow: - 0 4px 6px -1px rgba(0, 0, 0, 0.1), - 0 10px 15px -3px rgba(0, 0, 0, 0.1), - 0 20px 25px -5px rgba(0, 0, 0, 0.1); - overflow: hidden; - display: flex; - align-items: stretch; - min-height: 64px; - max-width: 100%; - animation: toast-slide-in 0.3s cubic-bezier(0.16, 1, 0.3, 1); - transform-origin: bottom right; - transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1); + display: flex; + align-items: flex-start; + gap: 0.75rem; + width: 24rem; + max-width: 90vw; + background: #FFFFFF; /* card-light */ + color: #2D3748; /* text-light */ + border: 1px solid #E2E8F0; /* border-light */ + border-left-width: 4px; + border-radius: 0.5rem; + padding: 0.75rem 0.75rem; + box-shadow: 0 10px 20px rgba(0,0,0,0.12), 0 3px 6px rgba(0,0,0,0.08); + opacity: 0; + transform: translateX(8px) scale(0.98); + transition: opacity 180ms ease, transform 180ms ease; + pointer-events: auto; /* clickable */ +} + +.dark .toast-notification { + background: #2D3748; /* card-dark */ + color: #E2E8F0; /* text-dark */ + border-color: #4A5568; /* border-dark */ } .toast-notification.hiding { - animation: toast-slide-out 0.3s cubic-bezier(0.16, 1, 0.3, 1); - opacity: 0; - transform: translateX(120%) scale(0.8); + opacity: 0; + transform: translateX(8px) scale(0.98); } -/* Dark theme */ -[data-theme="dark"] .toast-notification { - background: #1e293b; - box-shadow: - 0 4px 6px -1px rgba(0, 0, 0, 0.3), - 0 10px 15px -3px rgba(0, 0, 0, 0.3), - 0 20px 25px -5px rgba(0, 0, 0, 0.4); -} - -/* Accent bar on the left */ -.toast-notification::before { - content: ''; - width: 4px; - flex-shrink: 0; - transition: width 0.2s ease; -} - -.toast-notification:hover::before { - width: 6px; -} - -/* Type-based accent colors */ -.toast-notification.toast-success::before { - background: linear-gradient(to bottom, #10b981, #059669); -} - -.toast-notification.toast-error::before { - background: linear-gradient(to bottom, #ef4444, #dc2626); -} - -.toast-notification.toast-warning::before { - background: linear-gradient(to bottom, #f59e0b, #d97706); -} - -.toast-notification.toast-info::before { - background: linear-gradient(to bottom, #3b82f6, #2563eb); -} - -/* Icon area */ -.toast-icon { - display: flex; - align-items: center; - justify-content: center; - width: 48px; - flex-shrink: 0; - font-size: 20px; -} - -.toast-notification.toast-success .toast-icon { - color: #10b981; -} - -.toast-notification.toast-error .toast-icon { - color: #ef4444; -} - -.toast-notification.toast-warning .toast-icon { - color: #f59e0b; -} - -.toast-notification.toast-info .toast-icon { - color: #3b82f6; -} - -[data-theme="dark"] .toast-notification.toast-success .toast-icon { - color: #34d399; -} - -[data-theme="dark"] .toast-notification.toast-error .toast-icon { - color: #f87171; -} - -[data-theme="dark"] .toast-notification.toast-warning .toast-icon { - color: #fbbf24; -} - -[data-theme="dark"] .toast-notification.toast-info .toast-icon { - color: #60a5fa; -} - -/* Content area */ -.toast-content { - flex: 1; - padding: 12px 8px 12px 0; - display: flex; - flex-direction: column; - justify-content: center; - min-width: 0; -} - -.toast-title { - font-weight: 600; - font-size: 14px; - color: #0f172a; - margin: 0 0 4px 0; - line-height: 1.4; -} - -[data-theme="dark"] .toast-title { - color: #f1f5f9; -} - -.toast-message { - font-size: 13px; - color: #64748b; - margin: 0; - line-height: 1.5; - word-wrap: break-word; -} - -[data-theme="dark"] .toast-message { - color: #cbd5e1; -} +/* Icons */ +.toast-icon { line-height: 1; font-size: 1.125rem; padding-top: 0.125rem; } +.toast-title { font-weight: 600; margin-bottom: 0.125rem; } +.toast-message { font-size: 0.9375rem; } /* Close button */ .toast-close { - display: flex; - align-items: center; - justify-content: center; - width: 36px; - flex-shrink: 0; - background: transparent; - border: none; - color: #94a3b8; - cursor: pointer; - font-size: 16px; - transition: all 0.2s ease; - padding: 0; -} - -.toast-close:hover { - color: #475569; - transform: scale(1.1); -} - -.toast-close:active { - transform: scale(0.95); -} - -[data-theme="dark"] .toast-close { - color: #64748b; -} - -[data-theme="dark"] .toast-close:hover { - color: #cbd5e1; + margin-left: auto; + background: transparent; + border: 0; + color: inherit; + opacity: 0.7; + cursor: pointer; } +.toast-close:hover { opacity: 1; } /* Progress bar */ .toast-progress { - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: 3px; - background: rgba(0, 0, 0, 0.1); - overflow: hidden; + position: relative; + height: 2px; + overflow: hidden; + border-bottom-left-radius: 0.5rem; + border-bottom-right-radius: 0.5rem; + margin-top: 0.5rem; } - -[data-theme="dark"] .toast-progress { - background: rgba(255, 255, 255, 0.1); -} - .toast-progress-bar { - height: 100%; - background: currentColor; - transform-origin: left; - animation: toast-progress-shrink linear; + position: absolute; + left: 0; + top: 0; + height: 100%; + width: 100%; + animation-name: toast-progress-shrink; + animation-timing-function: linear; + animation-fill-mode: forwards; } -.toast-notification.toast-success .toast-progress-bar { - color: #10b981; -} +@keyframes toast-progress-shrink { from { width: 100%; } to { width: 0%; } } -.toast-notification.toast-error .toast-progress-bar { - color: #ef4444; -} +/* Variants */ +.toast-notification.toast-success { border-left-color: #10B981; } +.toast-notification.toast-error { border-left-color: #EF4444; } +.toast-notification.toast-warning { border-left-color: #F59E0B; } +.toast-notification.toast-info { border-left-color: #3B82F6; } -.toast-notification.toast-warning .toast-progress-bar { - color: #f59e0b; -} +.toast-notification.toast-success .toast-icon { color: #10B981; } +.toast-notification.toast-error .toast-icon { color: #EF4444; } +.toast-notification.toast-warning .toast-icon { color: #F59E0B; } +.toast-notification.toast-info .toast-icon { color: #3B82F6; } -.toast-notification.toast-info .toast-progress-bar { - color: #3b82f6; -} +.toast-notification.toast-success .toast-progress-bar { background: #10B981; } +.toast-notification.toast-error .toast-progress-bar { background: #EF4444; } +.toast-notification.toast-warning .toast-progress-bar { background: #F59E0B; } +.toast-notification.toast-info .toast-progress-bar { background: #3B82F6; } -/* Animations */ -@keyframes toast-slide-in { - from { - transform: translateX(120%) scale(0.8); - opacity: 0; - } - to { - transform: translateX(0) scale(1); - opacity: 1; - } -} - -@keyframes toast-slide-out { - from { - transform: translateX(0) scale(1); - opacity: 1; - } - to { - transform: translateX(120%) scale(0.8); - opacity: 0; - } -} - -@keyframes toast-progress-shrink { - from { - transform: scaleX(1); - } - to { - transform: scaleX(0); - } -} - -/* Hover to pause */ -.toast-notification:hover .toast-progress-bar { - animation-play-state: paused !important; -} - -/* Stacking behavior - limit to 5 visible toasts */ -.toast-notification:nth-child(n+6) { - display: none; -} - -/* Subtle scaling for stacked toasts */ -.toast-notification:nth-child(2) { - transform: scale(0.98) translateY(2px); - opacity: 0.95; -} - -.toast-notification:nth-child(3) { - transform: scale(0.96) translateY(4px); - opacity: 0.9; -} - -/* Accessibility */ -.toast-notification:focus-within { - outline: 2px solid #3b82f6; - outline-offset: 2px; -} - -/* Reduced motion support */ -@media (prefers-reduced-motion: reduce) { - .toast-notification { - animation: none; - transition: none; - } - - .toast-notification.hiding { - animation: none; - } - - .toast-progress-bar { - animation: none !important; - } -} - -/* Print - hide toasts */ -@media print { - #toast-notification-container { - display: none !important; - } -} diff --git a/app/static/toast-notifications.js b/app/static/toast-notifications.js index 11e25cf..79ff9e2 100644 --- a/app/static/toast-notifications.js +++ b/app/static/toast-notifications.js @@ -116,7 +116,7 @@ class ToastNotificationManager { closeBtn.className = 'toast-close'; closeBtn.setAttribute('type', 'button'); closeBtn.setAttribute('aria-label', 'Close notification'); - closeBtn.innerHTML = ''; + closeBtn.innerHTML = ''; } // Progress bar diff --git a/app/static/ui.css b/app/static/ui.css deleted file mode 100644 index 8b25305..0000000 --- a/app/static/ui.css +++ /dev/null @@ -1,87 +0,0 @@ -/* Shared UI utilities and extracted page styles */ - -/* Skip link accessibility */ -.skip-link { - position: absolute; - left: -999px; - top: 0; - background: var(--primary-color); - color: var(--text-on-primary); - padding: 8px 12px; - z-index: var(--z-fixed); - border-radius: var(--border-radius-sm); -} -.skip-link:focus { - left: 8px; - top: 8px; - outline: none; -} - -/* Mobile floating action button (Log Time) */ -.fab-log-time { - position: fixed; - right: 16px; - bottom: calc(var(--mobile-tabbar-height, 64px) + 16px); - width: 56px; - height: 56px; - border-radius: 50%; - background: var(--primary-color); - color: var(--text-on-primary) !important; - display: flex; - align-items: center; - justify-content: center; - box-shadow: 0 10px 20px rgba(0,0,0,0.15); - text-decoration: none; - transition: var(--transition); - z-index: var(--z-fixed); -} -.fab-log-time:hover { transform: translateY(-2px); box-shadow: 0 14px 24px rgba(0,0,0,0.2); } - -/* Invoices: extracted styles */ -.invoice-number-badge { - background: var(--primary-color); - color: #fff; - padding: 6px 12px; - border-radius: 20px; - font-weight: 600; - font-size: 14px; -} -.payment-badge { - padding: 4px 8px; - border-radius: 12px; - font-size: 11px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.3px; -} -.payment-status-info { min-width: 80px; } -.payment-progress { width: 60px; } -.payment-date { margin-top: 2px; } - -/* Projects: extracted styles */ -.project-badge { - background: var(--surface-variant); - color: var(--text-secondary); - padding: 4px 8px; - border-radius: var(--border-radius-sm); - font-size: 12px; - font-weight: var(--font-weight-medium); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); - cursor: default; -} - -/* Projects: table sorting indicators */ -thead th.sorted-asc::after { content: " \25B2"; color: var(--primary-color); font-weight: bold; } -thead th.sorted-desc::after { content: " \25BC"; color: var(--primary-color); font-weight: bold; } - -/* Detail sections (used on project view) */ -.invoice-section { padding: 12px 0; } -.section-title { font-size: 16px; font-weight: 600; border-bottom: 2px solid var(--primary-color); padding-bottom: 8px; } -.detail-row { display:flex; justify-content:space-between; align-items:center; margin-bottom:12px; padding:8px 0; border-bottom:1px solid var(--border-color); } -.detail-label { font-weight:600; color:var(--text-secondary); } -.detail-value { font-weight:600; color:var(--text-primary); } -.content-box { background: var(--light-color); padding: 16px; border-radius: 8px; border-left: 4px solid var(--primary-color); line-height: 1.6; } -@media (max-width:768px){ .detail-row{flex-direction:column; align-items:flex-start; gap:4px;} } - - diff --git a/app/templates/admin/dashboard.html b/app/templates/admin/dashboard.html new file mode 100644 index 0000000..4740c63 --- /dev/null +++ b/app/templates/admin/dashboard.html @@ -0,0 +1,55 @@ +{% extends "base.html" %} +{% from "components/cards.html" import info_card %} + +{% block content %} +
+
+

Admin Dashboard

+

System overview and management.

+
+
+ +
+ {{ info_card("Total Users", stats.total_users, "All time") }} + {{ info_card("Active Users", stats.active_users, "Currently active") }} + {{ info_card("Total Projects", stats.total_projects, "All time") }} + {{ info_card("Active Projects", stats.active_projects, "Currently active") }} +
+ +
+

Admin Sections

+ +
+ +
+

Recent Activity

+ + + + + + + + + + + {% for entry in recent_entries %} + + + + + + + {% else %} + + + + {% endfor %} + +
UserProjectDurationDate
{{ entry.user.username }}{{ entry.project.name }}{{ entry.duration }}{{ entry.start_time.strftime('%Y-%m-%d') }}
No recent activity.
+
+{% endblock %} diff --git a/app/templates/admin/settings.html b/app/templates/admin/settings.html new file mode 100644 index 0000000..8e757f7 --- /dev/null +++ b/app/templates/admin/settings.html @@ -0,0 +1,56 @@ +{% extends "base.html" %} + +{% block content %} +
+
+

Settings

+

Configure system-wide application settings.

+
+
+ +
+
+ + +
+ +
+

General

+
+
+ + +
+
+ + +
+
+
+ + +
+

Timers

+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ +
+ +
+
+
+{% endblock %} diff --git a/app/templates/admin/system_info.html b/app/templates/admin/system_info.html new file mode 100644 index 0000000..2f96c6c --- /dev/null +++ b/app/templates/admin/system_info.html @@ -0,0 +1,19 @@ +{% extends "base.html" %} +{% from "components/cards.html" import info_card %} + +{% block content %} +
+
+

System Information

+

Key metrics and statistics about the application.

+
+
+ +
+ {{ info_card("Total Users", total_users, "All time") }} + {{ info_card("Total Projects", total_projects, "All time") }} + {{ info_card("Total Time Entries", total_entries, "All time") }} + {{ info_card("Active Timers", active_timers, "Currently running") }} + {{ info_card("Database Size (MB)", db_size_mb, "Current size") }} +
+{% endblock %} diff --git a/app/templates/admin/user_form.html b/app/templates/admin/user_form.html new file mode 100644 index 0000000..5ef319d --- /dev/null +++ b/app/templates/admin/user_form.html @@ -0,0 +1,41 @@ +{% extends "base.html" %} + +{% block content %} +
+
+

{{ 'Edit User' if user else 'Create User' }}

+

+ {{ 'Update the details for %s.'|format(user.username) if user else 'Create a new user account.' }} +

+
+
+ +
+
+ +
+
+ + +
+
+ + +
+ {% if user %} +
+ + +
+ {% endif %} +
+
+ Cancel + +
+
+
+{% endblock %} diff --git a/app/templates/admin/users.html b/app/templates/admin/users.html new file mode 100644 index 0000000..6f6d711 --- /dev/null +++ b/app/templates/admin/users.html @@ -0,0 +1,44 @@ +{% extends "base.html" %} + +{% block content %} +
+
+

Manage Users

+

Add, edit, or remove user accounts.

+
+ Create User +
+ +
+ + + + + + + + + + + {% for user in users %} + + + + + + + {% else %} + + + + {% endfor %} + +
UsernameRoleStatusActions
{{ user.username }}{{ user.role | capitalize }} + + {{ 'Active' if user.is_active else 'Inactive' }} + + + Edit +
No users found.
+
+{% endblock %} diff --git a/app/templates/analytics/dashboard_improved.html b/app/templates/analytics/dashboard_improved.html index 7ea72fb..df97c24 100644 --- a/app/templates/analytics/dashboard_improved.html +++ b/app/templates/analytics/dashboard_improved.html @@ -3,321 +3,175 @@ {% block title %}{{ _('Analytics Dashboard') }} - {{ app_name }}{% endblock %} {% block content %} -
- {% from "_components.html" import page_header %} -
-
- {% set actions %} - - - - {% endset %} - {{ page_header('fas fa-chart-line', _('Analytics Dashboard'), _('Key metrics and actionable insights'), actions) }} -
+
+
+

{{ _('Analytics Dashboard') }}

+

{{ _('Key metrics and actionable insights') }}

- - -
-
-
-
-
- - - 0% - -
-

-

-

{{ _('Total Hours') }}

- {{ _('vs previous period') }} -
-
-
-
-
-
-
- - - 0% - -
-

-

-

{{ _('Billable Hours') }}

- 0% {{ _('of total') }} -
-
-
-
-
-
-
- - -
-

-

-

{{ _('Potential Revenue') }}

- {{ _('Avg rate:') }} - -
-
-
-
-
-
-
- - -
-

-

-

{{ _('Avg Daily Hours') }}

- 0 {{ _('active projects') }} -
-
-
+
+ + +
- - -
-
-
-
-
- {{ _('Insights & Recommendations') }} -
-
-
-
-
-
- {{ _('Loading...') }} -
-
-
-
-
-
-
- - -
-
-
-
-
- {{ _('Daily Hours Trend') }} -
-
- - -
-
-
-
- -
-
-
-
-
-
-
-
- {{ _('Billable Distribution') }} -
-
-
-
- -
-
-
-
-
- - -
-
-
-
-
- {{ _('Task Status Overview') }} -
-
-
-
-
-
- -
-
-
-
-
-

0

- {{ _('Tasks Completed') }} -
-
-

0

- {{ _('In Progress') }} -
-
-

0

- {{ _('To Do') }} -
-
-
-
-
-
-
-
-
-
-
- {{ _('Revenue by Project') }} -
-
-
-
- -
-
-
-
-
- - -
-
-
-
-
- {{ _('Hours by Project') }} -
-
-
-
- -
-
-
-
-
-
-
-
- {{ _('Weekly Trends') }} -
-
-
-
- -
-
-
-
-
- - -
-
-
-
-
- {{ _('Hours by Time of Day') }} -
-
-
-
- -
-
-
-
-
-
-
-
- {{ _('Project Completion Rate') }} -
-
-
-
- -
-
-
-
-
- - - {% if current_user.is_admin %} -
-
-
-
-
- {{ _('User Performance') }} -
-
-
-
- -
-
-
-
-
- {% endif %}
- -