/* ============================================================ Fusion Clock - Portal Dark Theme A modern, mobile-first attendance interface ============================================================ */ /* ---- Light theme (default) ---- */ .fclk-app { --fclk-bg: #f3f4f6; --fclk-card: #ffffff; --fclk-card-border: #e5e7eb; --fclk-text: #1f2937; --fclk-text-muted: #6b7280; --fclk-text-dim: #9ca3af; --fclk-green: #10B981; --fclk-green-glow: rgba(16, 185, 129, 0.25); --fclk-red: #ef4444; --fclk-red-glow: rgba(239, 68, 68, 0.25); --fclk-blue: #3b82f6; --fclk-hover-bg: #f9fafb; --fclk-overlay-bg: rgba(243, 244, 246, 0.85); --fclk-shadow: 0 1px 3px rgba(0, 0, 0, 0.06); --fclk-toast-bg: #ffffff; margin: -16px -15px; padding: 0; min-height: 100vh; background: var(--fclk-bg); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; } /* ---- Dark theme: OS preference OR Odoo dark mode class ---- */ @media (prefers-color-scheme: dark) { .fclk-app { --fclk-bg: #0f1117; --fclk-card: #1a1d23; --fclk-card-border: #2a2d35; --fclk-text: #ffffff; --fclk-text-muted: #9ca3af; --fclk-text-dim: #6b7280; --fclk-green-glow: rgba(16, 185, 129, 0.3); --fclk-red-glow: rgba(239, 68, 68, 0.3); --fclk-hover-bg: #1e2128; --fclk-overlay-bg: rgba(15, 17, 23, 0.85); --fclk-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); --fclk-toast-bg: #1a1d23; } } html.o_dark .fclk-app, .fclk-app.fclk-dark { --fclk-bg: #0f1117; --fclk-card: #1a1d23; --fclk-card-border: #2a2d35; --fclk-text: #ffffff; --fclk-text-muted: #9ca3af; --fclk-text-dim: #6b7280; --fclk-green-glow: rgba(16, 185, 129, 0.3); --fclk-red-glow: rgba(239, 68, 68, 0.3); --fclk-hover-bg: #1e2128; --fclk-overlay-bg: rgba(15, 17, 23, 0.85); --fclk-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); --fclk-toast-bg: #1a1d23; } .fclk-app * { box-sizing: border-box; } /* Hide portal navigation and footer */ .fclk-app ~ .o_portal_navbar, .fclk-app .o_portal_navbar { display: none !important; } .fclk-app ~ footer, .fclk-app ~ .o_footer, .fclk-app ~ .o_footer_copyright { display: none !important; } body:has(.fclk-app) footer, body:has(.fclk-app) .o_footer { display: none !important; } /* Full-bleed: never let the portal layout's white chrome show as a border around the dark app. Match the PAGE background to the app's background in both themes (so the wrapper's container padding reads as an invisible gutter) and clip horizontal overflow from the .fclk-app full-bleed margins. */ html:has(.fclk-app), body:has(.fclk-app) { background: #f3f4f6; overflow-x: hidden; } @media (prefers-color-scheme: dark) { html:has(.fclk-app), body:has(.fclk-app) { background: #0f1117; } } html.o_dark:has(.fclk-app), html.o_dark body:has(.fclk-app), body:has(.fclk-app.fclk-dark) { background: #0f1117; } .fclk-container { max-width: 480px; margin: 0 auto; padding: 24px 20px 100px; position: relative; } /* ---- Header ---- */ .fclk-header { margin-bottom: 20px; } .fclk-date { color: var(--fclk-text-muted); font-size: 14px; margin-bottom: 4px; } .fclk-greeting { color: var(--fclk-text); font-size: 28px; font-weight: 700; margin: 0; letter-spacing: -0.5px; } /* ---- Status Card ---- */ .fclk-status-card { background: var(--fclk-card); border: 1px solid var(--fclk-card-border); border-radius: 16px; padding: 16px 20px; margin-bottom: 32px; box-shadow: var(--fclk-shadow); } .fclk-status-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; } .fclk-status-indicator { display: flex; align-items: center; gap: 8px; } .fclk-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--fclk-text-dim); display: inline-block; transition: all 0.3s ease; } .fclk-dot-active { background: var(--fclk-green); box-shadow: 0 0 8px var(--fclk-green-glow); animation: fclk-pulse 2s ease-in-out infinite; } @keyframes fclk-pulse { 0%, 100% { box-shadow: 0 0 4px var(--fclk-green-glow); } 50% { box-shadow: 0 0 16px var(--fclk-green-glow); } } .fclk-status-text { color: var(--fclk-text); font-size: 14px; font-weight: 500; } .fclk-current-time { color: var(--fclk-text-muted); font-size: 13px; } /* ---- Location Card ---- */ .fclk-location-card { display: flex; align-items: center; gap: 12px; background: rgba(16, 185, 129, 0.08); border: 1px solid rgba(16, 185, 129, 0.15); border-radius: 12px; padding: 12px 16px; cursor: pointer; transition: all 0.2s ease; } .fclk-location-card:hover { background: rgba(16, 185, 129, 0.12); border-color: rgba(16, 185, 129, 0.25); } .fclk-location-icon { flex-shrink: 0; width: 36px; height: 36px; background: rgba(16, 185, 129, 0.15); border-radius: 10px; display: flex; align-items: center; justify-content: center; } .fclk-location-info { flex: 1; min-width: 0; } .fclk-location-name { color: var(--fclk-text); font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .fclk-location-address { color: var(--fclk-text-muted); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .fclk-location-arrow { flex-shrink: 0; opacity: 0.5; } /* ---- Scheduled Shift Card ---- */ .fclk-schedule-card { display: flex; align-items: center; gap: 12px; background: var(--fclk-card); border: 1px solid var(--fclk-card-border); border-radius: 14px; padding: 14px 16px; margin: -14px 0 28px; box-shadow: var(--fclk-shadow); } .fclk-schedule-icon { width: 38px; height: 38px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; border-radius: 10px; background: rgba(59, 130, 246, 0.12); color: var(--fclk-blue); font-size: 16px; } .fclk-schedule-info { min-width: 0; flex: 1; } .fclk-schedule-label { color: var(--fclk-text-muted); font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; } .fclk-schedule-value { color: var(--fclk-text); font-size: 14px; font-weight: 650; margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .fclk-schedule-hours { color: var(--fclk-text); font-size: 18px; font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; } /* ---- Timer Section ---- */ .fclk-timer-section { text-align: center; margin-bottom: 28px; } .fclk-timer-label { color: var(--fclk-text-muted); font-size: 13px; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 12px; } .fclk-timer { color: var(--fclk-text); font-size: clamp(32px, 10vw, 52px); font-weight: 300; letter-spacing: 2px; font-variant-numeric: tabular-nums; font-family: 'SF Mono', 'Fira Code', 'Courier New', monospace; white-space: nowrap; } /* ---- Clock Button ---- */ .fclk-button-section { text-align: center; margin-bottom: 36px; } .fclk-clock-btn { width: 120px; height: 120px; border-radius: 50%; border: none; background: linear-gradient(135deg, #10B981, #059669); box-shadow: 0 8px 32px var(--fclk-green-glow), 0 0 0 0 var(--fclk-green-glow); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; position: relative; overflow: hidden; transition: all 0.3s ease; outline: none; -webkit-tap-highlight-color: transparent; } .fclk-clock-btn:hover { transform: scale(1.05); box-shadow: 0 12px 40px var(--fclk-green-glow); } .fclk-clock-btn:active { transform: scale(0.95); } .fclk-clock-btn-out { background: linear-gradient(135deg, #ef4444, #dc2626); box-shadow: 0 8px 32px var(--fclk-red-glow); animation: fclk-btn-pulse 2s ease-in-out infinite; } .fclk-clock-btn-out:hover { box-shadow: 0 12px 40px var(--fclk-red-glow); } @keyframes fclk-btn-pulse { 0%, 100% { box-shadow: 0 8px 32px var(--fclk-red-glow); } 50% { box-shadow: 0 8px 48px var(--fclk-red-glow), 0 0 0 12px rgba(239, 68, 68, 0.1); } } .fclk-btn-icon { position: relative; z-index: 1; } #fclk-btn-icon-play { transform: translateX(4px); } .fclk-btn-ripple { position: absolute; top: 50%; left: 50%; width: 0; height: 0; border-radius: 50%; background: rgba(255, 255, 255, 0.3); transform: translate(-50%, -50%); pointer-events: none; } .fclk-btn-ripple.fclk-ripple-active { animation: fclk-ripple 0.6s ease-out; } @keyframes fclk-ripple { from { width: 0; height: 0; opacity: 1; } to { width: 200px; height: 200px; opacity: 0; } } .fclk-btn-label { color: var(--fclk-text-muted); font-size: 14px; margin-top: 16px; } /* ---- Stats Row ---- */ .fclk-stats-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 28px; } .fclk-stat-card { background: var(--fclk-card); border: 1px solid var(--fclk-card-border); border-radius: 16px; padding: 16px; box-shadow: var(--fclk-shadow); } .fclk-stat-header { display: flex; align-items: center; gap: 6px; color: var(--fclk-text-muted); font-size: 12px; margin-bottom: 8px; } .fclk-stat-value { color: var(--fclk-text); font-size: 32px; font-weight: 700; line-height: 1; margin-bottom: 4px; } .fclk-stat-target { color: var(--fclk-text-dim); font-size: 12px; } /* ---- Request Leave Button ---- */ .fclk-leave-btn { display: flex; align-items: center; gap: 10px; width: 100%; background: var(--fclk-card); border: 1px solid var(--fclk-card-border); border-radius: 14px; padding: 16px 20px; margin-bottom: 28px; color: var(--fclk-text); font-size: 14px; font-weight: 500; cursor: pointer; transition: all 0.2s ease; box-shadow: var(--fclk-shadow); text-align: left; font-family: inherit; } .fclk-leave-btn svg:first-child { color: var(--fclk-green); flex-shrink: 0; } .fclk-leave-btn-arrow { margin-left: auto; color: var(--fclk-text-dim); flex-shrink: 0; transition: transform 0.2s ease; } .fclk-leave-btn:hover { background: var(--fclk-hover-bg); border-color: rgba(16, 185, 129, 0.3); } .fclk-leave-btn:hover .fclk-leave-btn-arrow { transform: translateX(2px); } .fclk-leave-btn:active { transform: scale(0.99); } /* ---- Recent Activity ---- */ .fclk-recent-section { margin-bottom: 24px; } .fclk-recent-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; } .fclk-recent-header h3 { color: var(--fclk-text); font-size: 18px; font-weight: 600; margin: 0; } .fclk-view-all { color: var(--fclk-blue); font-size: 13px; text-decoration: none; } .fclk-recent-list { display: flex; flex-direction: column; gap: 8px; } .fclk-recent-item { display: flex; align-items: center; gap: 14px; background: var(--fclk-card); border: 1px solid var(--fclk-card-border); border-radius: 12px; padding: 14px 16px; transition: background 0.2s ease; } .fclk-recent-item:hover { background: var(--fclk-hover-bg); } .fclk-recent-date { text-align: center; min-width: 40px; } .fclk-recent-day-name { color: var(--fclk-text-muted); font-size: 11px; text-transform: uppercase; } .fclk-recent-day-num { color: var(--fclk-text); font-size: 22px; font-weight: 700; line-height: 1.1; } .fclk-recent-info { flex: 1; min-width: 0; } .fclk-recent-location { color: var(--fclk-text); font-size: 14px; font-weight: 500; } .fclk-recent-times { color: var(--fclk-text-muted); font-size: 12px; } .fclk-recent-hours { color: var(--fclk-text); font-size: 16px; font-weight: 600; flex-shrink: 0; } .fclk-recent-empty { text-align: center; color: var(--fclk-text-dim); padding: 24px; font-size: 14px; } /* ---- Bottom Navigation ---- */ .fclk-nav-bar { position: fixed; bottom: 0; left: 0; right: 0; background: var(--fclk-card); border-top: 1px solid var(--fclk-card-border); display: flex; justify-content: center; gap: 0; padding: 8px 0; padding-bottom: max(8px, env(safe-area-inset-bottom)); z-index: 100; max-width: 100%; } .fclk-nav-item { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 8px 24px; color: var(--fclk-text-dim); text-decoration: none; font-size: 11px; transition: color 0.2s ease; } .fclk-nav-item:hover, .fclk-nav-active { color: var(--fclk-green); text-decoration: none; } /* ---- Legacy Modal (location picker still uses this) ---- */ .fclk-modal { position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 200; display: flex; align-items: flex-end; justify-content: center; } .fclk-modal-backdrop { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.35); backdrop-filter: blur(4px); } .fclk-modal-content { position: relative; background: var(--fclk-card); border-radius: 20px 20px 0 0; padding: 24px 20px 40px; width: 100%; max-width: 480px; max-height: 60vh; overflow-y: auto; animation: fclk-slide-up 0.3s ease-out; } .fclk-modal-content h3 { color: var(--fclk-text); font-size: 18px; font-weight: 600; margin: 0 0 16px; } @keyframes fclk-slide-up { from { transform: translateY(100%); } to { transform: translateY(0); } } /* ============================================================ Wizard Dialogs - Professional modals for reasons, confirmations Theme-aware, works in both light and dark mode ============================================================ */ /* Standalone fallbacks for wizard modals rendered outside .fclk-app */ .fclk-wizard-overlay { --fclk-wiz-card: #ffffff; --fclk-wiz-card-border: #e5e7eb; --fclk-wiz-bg: #f3f4f6; --fclk-wiz-text: #1f2937; --fclk-wiz-text-muted: #6b7280; --fclk-wiz-text-dim: #9ca3af; --fclk-wiz-green: #10B981; --fclk-wiz-green-glow: rgba(16, 185, 129, 0.25); --fclk-wiz-hover-bg: #f9fafb; position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 1055; display: flex; align-items: center; justify-content: center; padding: 20px; } @media (prefers-color-scheme: dark) { .fclk-wizard-overlay { --fclk-wiz-card: #1a1d23; --fclk-wiz-card-border: #2a2d35; --fclk-wiz-bg: #0f1117; --fclk-wiz-text: #ffffff; --fclk-wiz-text-muted: #9ca3af; --fclk-wiz-text-dim: #6b7280; --fclk-wiz-green-glow: rgba(16, 185, 129, 0.3); --fclk-wiz-hover-bg: #1e2128; } } html.o_dark .fclk-wizard-overlay { --fclk-wiz-card: #1a1d23; --fclk-wiz-card-border: #2a2d35; --fclk-wiz-bg: #0f1117; --fclk-wiz-text: #ffffff; --fclk-wiz-text-muted: #9ca3af; --fclk-wiz-text-dim: #6b7280; --fclk-wiz-green-glow: rgba(16, 185, 129, 0.3); --fclk-wiz-hover-bg: #1e2128; } .fclk-wizard-backdrop { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); } .fclk-wizard-dialog { position: relative; background: var(--fclk-wiz-card, #ffffff); border: 1px solid var(--fclk-wiz-card-border, #e5e7eb); border-radius: 20px; width: 100%; max-width: 440px; max-height: 85vh; overflow-y: auto; box-shadow: 0 24px 80px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(255, 255, 255, 0.05); animation: fclk-wizard-enter 0.3s cubic-bezier(0.32, 0.72, 0, 1); } .fclk-wizard-dialog--compact { max-width: 380px; } @keyframes fclk-wizard-enter { from { opacity: 0; transform: scale(0.95) translateY(8px); } to { opacity: 1; transform: scale(1) translateY(0); } } .fclk-wizard-header { padding: 28px 24px 20px; text-align: center; border-bottom: 1px solid var(--fclk-wiz-card-border, #e5e7eb); } .fclk-wizard-header-icon { width: 56px; height: 56px; border-radius: 16px; display: inline-flex; align-items: center; justify-content: center; margin-bottom: 16px; } .fclk-wizard-header--warning .fclk-wizard-header-icon { background: rgba(245, 158, 11, 0.12); color: #f59e0b; } .fclk-wizard-header--danger .fclk-wizard-header-icon { background: rgba(239, 68, 68, 0.12); color: #ef4444; } .fclk-wizard-header--info .fclk-wizard-header-icon { background: rgba(59, 130, 246, 0.12); color: #3b82f6; } .fclk-wizard-title { color: var(--fclk-wiz-text, #1f2937); font-size: 20px; font-weight: 700; margin: 0 0 6px; letter-spacing: -0.3px; } .fclk-wizard-subtitle { color: var(--fclk-wiz-text-muted, #6b7280); font-size: 13px; line-height: 1.5; margin: 0; } .fclk-wizard-body { padding: 24px; } .fclk-wizard-field { margin-bottom: 20px; } .fclk-wizard-field:last-child { margin-bottom: 0; } .fclk-wizard-label { display: flex; align-items: center; gap: 6px; color: var(--fclk-wiz-text, #1f2937); font-size: 13px; font-weight: 600; margin-bottom: 8px; } .fclk-wizard-label svg { color: var(--fclk-wiz-text-muted, #6b7280); flex-shrink: 0; } .fclk-wizard-required { color: #ef4444; font-weight: 700; } .fclk-wizard-input { width: 100%; background: var(--fclk-wiz-bg, #f3f4f6); border: 1.5px solid var(--fclk-wiz-card-border, #e5e7eb); border-radius: 12px; padding: 12px 14px; font-size: 14px; color: var(--fclk-wiz-text, #1f2937); transition: border-color 0.2s, box-shadow 0.2s; outline: none; font-family: inherit; } .fclk-wizard-input:focus { border-color: var(--fclk-wiz-green, #10B981); box-shadow: 0 0 0 3px var(--fclk-wiz-green-glow, rgba(16, 185, 129, 0.25)); } .fclk-wizard-input::placeholder { color: var(--fclk-wiz-text-dim, #9ca3af); } .fclk-wizard-textarea { resize: vertical; min-height: 80px; } .fclk-wizard-hint { display: block; color: var(--fclk-wiz-text-dim, #9ca3af); font-size: 11px; margin-top: 6px; } .fclk-wizard-footer { padding: 16px 24px 20px; display: flex; gap: 10px; justify-content: flex-end; border-top: 1px solid var(--fclk-wiz-card-border, #e5e7eb); } .fclk-wizard-btn { display: inline-flex; align-items: center; gap: 6px; padding: 10px 20px; border-radius: 12px; font-size: 13px; font-weight: 600; cursor: pointer; border: none; transition: all 0.2s ease; letter-spacing: 0.2px; } .fclk-wizard-btn:disabled { opacity: 0.5; cursor: not-allowed; } .fclk-wizard-btn--primary { background: linear-gradient(135deg, #10B981, #059669); color: #fff; box-shadow: 0 2px 8px rgba(16, 185, 129, 0.3); } .fclk-wizard-btn--primary:hover:not(:disabled) { box-shadow: 0 4px 16px rgba(16, 185, 129, 0.4); transform: translateY(-1px); } .fclk-wizard-btn--danger { background: linear-gradient(135deg, #ef4444, #dc2626); color: #fff; box-shadow: 0 2px 8px rgba(239, 68, 68, 0.3); } .fclk-wizard-btn--danger:hover:not(:disabled) { box-shadow: 0 4px 16px rgba(239, 68, 68, 0.4); transform: translateY(-1px); } .fclk-wizard-btn--secondary { background: var(--fclk-wiz-bg, #f3f4f6); color: var(--fclk-wiz-text-muted, #6b7280); border: 1px solid var(--fclk-wiz-card-border, #e5e7eb); } .fclk-wizard-btn--secondary:hover:not(:disabled) { background: var(--fclk-wiz-hover-bg, #f9fafb); color: var(--fclk-wiz-text, #1f2937); } /* Clock-out confirmation summary card */ .fclk-clockout-summary { background: var(--fclk-wiz-bg, #f3f4f6); border: 1px solid var(--fclk-wiz-card-border, #e5e7eb); border-radius: 12px; padding: 16px; } .fclk-clockout-summary-row { display: flex; justify-content: space-between; align-items: center; padding: 8px 0; } .fclk-clockout-summary-row + .fclk-clockout-summary-row { border-top: 1px solid var(--fclk-wiz-card-border, #e5e7eb); } .fclk-clockout-summary-label { color: var(--fclk-wiz-text-muted, #6b7280); font-size: 13px; } .fclk-clockout-summary-value { color: var(--fclk-wiz-text, #1f2937); font-size: 14px; font-weight: 600; } .fclk-modal-list { display: flex; flex-direction: column; gap: 8px; } .fclk-modal-item { display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: 12px; cursor: pointer; transition: background 0.2s ease; } .fclk-modal-item:hover { background: rgba(16, 185, 129, 0.08); } .fclk-modal-item-icon { flex-shrink: 0; } .fclk-modal-item-name { color: var(--fclk-wiz-text, #1f2937); font-size: 14px; font-weight: 500; } .fclk-modal-item-addr { color: var(--fclk-wiz-text-muted, #6b7280); font-size: 12px; } /* ---- Toast ---- */ .fclk-toast { position: fixed; top: 24px; left: 50%; transform: translateX(-50%); background: var(--fclk-toast-bg, var(--fclk-card)); border: 1px solid var(--fclk-card-border); border-radius: 12px; padding: 12px 20px; display: flex; align-items: center; gap: 10px; z-index: 300; box-shadow: var(--fclk-shadow); animation: fclk-toast-in 0.3s ease-out; max-width: 90%; } .fclk-toast-success { border-color: var(--fclk-green); } .fclk-toast-error { border-color: var(--fclk-red); } @keyframes fclk-toast-in { from { transform: translateX(-50%) translateY(-20px); opacity: 0; } to { transform: translateX(-50%) translateY(0); opacity: 1; } } @keyframes fclk-toast-out { from { transform: translateX(-50%) translateY(0); opacity: 1; } to { transform: translateX(-50%) translateY(-20px); opacity: 0; } } .fclk-toast-msg { color: var(--fclk-text); font-size: 14px; } /* ---- GPS Overlay ---- */ .fclk-gps-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: var(--fclk-overlay-bg); backdrop-filter: blur(8px); display: flex; flex-direction: column; align-items: center; justify-content: center; z-index: 250; gap: 16px; } .fclk-gps-spinner { width: 48px; height: 48px; border: 3px solid var(--fclk-card-border); border-top: 3px solid var(--fclk-green); border-radius: 50%; animation: fclk-spin 0.8s linear infinite; } @keyframes fclk-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .fclk-gps-text { color: var(--fclk-text-muted); font-size: 14px; } /* ---- Error Shake ---- */ .fclk-shake { animation: fclk-shake 0.5s ease-in-out; } @keyframes fclk-shake { 0%, 100% { transform: translateX(0); } 20% { transform: translateX(-10px); } 40% { transform: translateX(10px); } 60% { transform: translateX(-6px); } 80% { transform: translateX(6px); } } /* ---- Responsive ---- */ @media (max-width: 420px) { .fclk-clock-btn { width: 100px; height: 100px; } .fclk-clock-btn svg { width: 36px; height: 36px; } .fclk-stat-value { font-size: 26px; } } /* ---- Timesheet Page ---- */ .fclk-timesheet-container { max-width: 600px; margin: 0 auto; padding: 24px 20px 100px; } .fclk-ts-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .fclk-ts-header h2 { color: var(--fclk-text); font-size: 22px; font-weight: 700; margin: 0; } .fclk-ts-period-nav { display: flex; gap: 8px; } .fclk-ts-period-btn { background: var(--fclk-card); border: 1px solid var(--fclk-card-border); color: var(--fclk-text-muted); padding: 8px 16px; border-radius: 8px; font-size: 13px; cursor: pointer; text-decoration: none; transition: all 0.2s ease; } .fclk-ts-period-btn:hover, .fclk-ts-period-btn-active { background: var(--fclk-green); color: white; border-color: var(--fclk-green); text-decoration: none; } .fclk-ts-summary { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 24px; } .fclk-ts-summary-card { background: var(--fclk-card); border: 1px solid var(--fclk-card-border); border-radius: 12px; padding: 16px; text-align: center; } .fclk-ts-summary-value { color: var(--fclk-text); font-size: 24px; font-weight: 700; } .fclk-ts-summary-label { color: var(--fclk-text-muted); font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; margin-top: 4px; } .fclk-ts-table { width: 100%; border-collapse: separate; border-spacing: 0 6px; } .fclk-ts-table th { color: var(--fclk-text-muted); font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; padding: 8px 12px; text-align: left; font-weight: 500; } .fclk-ts-table td { background: var(--fclk-card); color: var(--fclk-text); font-size: 13px; padding: 12px; } .fclk-ts-table tr td:first-child { border-radius: 8px 0 0 8px; } .fclk-ts-table tr td:last-child { border-radius: 0 8px 8px 0; } .fclk-ts-badge-auto { background: rgba(239, 68, 68, 0.15); color: var(--fclk-red); font-size: 10px; padding: 2px 6px; border-radius: 4px; } /* Responsive timesheet entries — stacked cards instead of a cramped table. Reads cleanly at any phone/tablet width; no horizontal overflow. */ .fclk-ts-list { display: flex; flex-direction: column; gap: 10px; } .fclk-ts-card { background: var(--fclk-card); border: 1px solid var(--fclk-card-border); border-radius: 12px; padding: 14px 16px; } .fclk-ts-card-top { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; } .fclk-ts-card-date { color: var(--fclk-text); font-size: 14px; font-weight: 700; } .fclk-ts-card-date span { color: var(--fclk-text-dim); font-weight: 400; margin-left: 6px; } .fclk-ts-card-net { color: var(--fclk-green); font-weight: 700; font-size: 15px; white-space: nowrap; } .fclk-ts-card-times { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 8px; color: var(--fclk-text); font-size: 14px; } .fclk-ts-arrow { color: var(--fclk-text-dim); } .fclk-ts-k { color: var(--fclk-text-dim); font-size: 11px; text-transform: uppercase; letter-spacing: 0.4px; margin-right: 4px; } .fclk-ts-card-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 8px; color: var(--fclk-text-muted); font-size: 12px; } .fclk-ts-dot { color: var(--fclk-text-dim); } .fclk-ts-correct { margin-left: auto; color: var(--fclk-text-muted); font-size: 12px; text-decoration: none; } .fclk-ts-correct:hover { color: var(--fclk-green); text-decoration: underline; } /* ---- Reports Page ---- */ .fclk-reports-container { max-width: 600px; margin: 0 auto; padding: 24px 20px 100px; } .fclk-report-item { display: flex; align-items: center; justify-content: space-between; background: var(--fclk-card); border: 1px solid var(--fclk-card-border); border-radius: 12px; padding: 16px; margin-bottom: 8px; transition: background 0.2s ease; } .fclk-report-item:hover { background: var(--fclk-hover-bg); } .fclk-report-info h4 { color: var(--fclk-text); font-size: 14px; font-weight: 600; margin: 0 0 4px; } .fclk-report-info p { color: var(--fclk-text-muted); font-size: 12px; margin: 0; } .fclk-report-download { background: var(--fclk-green); color: white; border: none; border-radius: 8px; padding: 8px 16px; font-size: 13px; font-weight: 500; cursor: pointer; text-decoration: none; transition: opacity 0.2s; } .fclk-report-download:hover { opacity: 0.85; color: white; text-decoration: none; } .fclk-empty-state { text-align: center; color: var(--fclk-text-dim); padding: 48px 24px; font-size: 14px; } .fclk-empty-state svg { margin-bottom: 12px; opacity: 0.4; } /* ============================================================ Portal FAB - Floating clock-in/out button on all portal pages Matches the backend FAB design (gradient, ripple, theme-aware) ============================================================ */ /* ---- Theme tokens (light default) ---- */ #fclk-portal-fab { --pfab-panel-bg: #ffffff; --pfab-panel-border: #e5e7eb; --pfab-panel-shadow: 0 8px 32px rgba(0, 0, 0, 0.12); --pfab-text: #1f2937; --pfab-muted: #6b7280; --pfab-divider: #e5e7eb; --pfab-loc-bg: rgba(16, 185, 129, 0.08); --pfab-error-bg: rgba(239, 68, 68, 0.06); --pfab-arrow-bg: #ffffff; --pfab-green: #10B981; --pfab-red: #ef4444; --pfab-teal: #0d9488; --pfab-blue: #2563eb; } /* ---- Dark theme (OS preference) ---- */ @media (prefers-color-scheme: dark) { #fclk-portal-fab { --pfab-panel-bg: #1e2028; --pfab-panel-border: #3a3d48; --pfab-panel-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); --pfab-text: #f1f1f4; --pfab-muted: #9ca3af; --pfab-divider: #3a3d48; --pfab-loc-bg: rgba(16, 185, 129, 0.1); --pfab-error-bg: rgba(239, 68, 68, 0.1); --pfab-arrow-bg: #1e2028; } } /* ---- Dark theme (Odoo class) ---- */ html.o_dark #fclk-portal-fab { --pfab-panel-bg: #1e2028; --pfab-panel-border: #3a3d48; --pfab-panel-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); --pfab-text: #f1f1f4; --pfab-muted: #9ca3af; --pfab-divider: #3a3d48; --pfab-loc-bg: rgba(16, 185, 129, 0.1); --pfab-error-bg: rgba(239, 68, 68, 0.1); --pfab-arrow-bg: #1e2028; } /* ---- Wrapper: bottom-left, like the backend FAB ---- */ #fclk-portal-fab { position: fixed; bottom: 24px; left: 24px; z-index: 1050; display: flex; flex-direction: column-reverse; align-items: flex-start; gap: 12px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; } /* ---- FAB Button ---- */ .fclk-pfab-btn { position: relative; width: 54px; height: 54px; border-radius: 50%; border: none; background: linear-gradient(135deg, var(--pfab-teal) 0%, var(--pfab-blue) 100%); color: #fff; font-size: 21px; cursor: pointer; box-shadow: 0 4px 20px rgba(13, 148, 136, 0.35); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); display: flex; align-items: center; justify-content: center; outline: none; overflow: visible; -webkit-tap-highlight-color: transparent; } .fclk-pfab-btn:hover { transform: scale(1.1); box-shadow: 0 6px 28px rgba(13, 148, 136, 0.45); } .fclk-pfab-btn:active { transform: scale(0.93); } /* Active (clocked in): green-teal gradient */ .fclk-pfab-btn--active { background: linear-gradient(135deg, var(--pfab-green) 0%, var(--pfab-teal) 100%); box-shadow: 0 4px 20px rgba(16, 185, 129, 0.4); } .fclk-pfab-btn--active:hover { box-shadow: 0 6px 28px rgba(16, 185, 129, 0.5); } .fclk-pfab-icon { position: relative; z-index: 2; line-height: 1; } /* ---- Ripple rings (only visible when clocked in) ---- */ .fclk-pfab-ripple-ring { position: absolute; top: 50%; left: 50%; width: 54px; height: 54px; border-radius: 50%; border: 2px solid rgba(16, 185, 129, 0.5); transform: translate(-50%, -50%) scale(1); pointer-events: none; z-index: 1; opacity: 0; } /* Only animate ripples when clocked in */ .fclk-pfab--active .fclk-pfab-ripple-ring--1 { animation: fclk-pfab-ripple-out 2.4s ease-out infinite; } .fclk-pfab--active .fclk-pfab-ripple-ring--2 { animation: fclk-pfab-ripple-out 2.4s ease-out 0.8s infinite; } .fclk-pfab--active .fclk-pfab-ripple-ring--3 { animation: fclk-pfab-ripple-out 2.4s ease-out 1.6s infinite; } @keyframes fclk-pfab-ripple-out { 0% { transform: translate(-50%, -50%) scale(1); opacity: 0.55; } 100% { transform: translate(-50%, -50%) scale(2.6); opacity: 0; } } /* ---- Mini timer badge ---- */ .fclk-pfab-badge { position: absolute; top: -8px; left: 50%; transform: translateX(-50%); background: #111827; color: var(--pfab-green); font-size: 9px; font-weight: 700; font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; padding: 2px 7px; border-radius: 10px; white-space: nowrap; letter-spacing: 0.5px; border: 1px solid rgba(16, 185, 129, 0.35); pointer-events: none; z-index: 3; animation: fclk-pfab-badge-in 0.3s ease; } @keyframes fclk-pfab-badge-in { from { opacity: 0; transform: translateX(-50%) translateY(4px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } } /* ---- Expandable Panel ---- */ .fclk-pfab-panel { width: 280px; background: var(--pfab-panel-bg); border: 1px solid var(--pfab-panel-border); border-radius: 16px; padding: 18px; box-shadow: var(--pfab-panel-shadow); position: relative; animation: fclk-pfab-panel-in 0.25s cubic-bezier(0.4, 0, 0.2, 1); } .fclk-pfab-panel--open { display: block; } @keyframes fclk-pfab-panel-in { from { opacity: 0; transform: translateY(12px) scale(0.96); } to { opacity: 1; transform: translateY(0) scale(1); } } /* Arrow pointing down toward the FAB */ .fclk-pfab-panel-arrow { position: absolute; bottom: -6px; left: 22px; width: 12px; height: 12px; background: var(--pfab-arrow-bg); border-right: 1px solid var(--pfab-panel-border); border-bottom: 1px solid var(--pfab-panel-border); transform: rotate(45deg); } /* ---- Panel Header ---- */ .fclk-pfab-panel-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px; } .fclk-pfab-panel-title { display: flex; align-items: center; gap: 8px; color: var(--pfab-text); font-size: 13px; font-weight: 600; letter-spacing: 0.3px; } .fclk-pfab-status-dot { width: 8px; height: 8px; border-radius: 50%; background: #9ca3af; flex-shrink: 0; display: inline-block; } .fclk-pfab-status-dot--active { background: var(--pfab-green); box-shadow: 0 0 6px rgba(16, 185, 129, 0.5); } .fclk-pfab-status-text { color: var(--pfab-text); } .fclk-pfab-open-link { color: var(--pfab-muted); font-size: 13px; text-decoration: none; transition: color 0.2s; } .fclk-pfab-open-link:hover { color: var(--pfab-blue); text-decoration: none; } /* ---- Location chip ---- */ .fclk-pfab-location { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--pfab-green); background: var(--pfab-loc-bg); border-radius: 8px; padding: 6px 10px; margin-bottom: 12px; } .fclk-pfab-location .fa { font-size: 12px; } /* ---- Timer ---- */ .fclk-pfab-timer { text-align: center; color: var(--pfab-text); font-size: 28px; font-weight: 300; font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; letter-spacing: 2px; font-variant-numeric: tabular-nums; margin-bottom: 14px; line-height: 1; } /* ---- Stats row ---- */ .fclk-pfab-stats { display: flex; align-items: center; justify-content: center; gap: 16px; margin-bottom: 14px; } .fclk-pfab-stat { text-align: center; } .fclk-pfab-stat-val { display: block; color: var(--pfab-text); font-size: 16px; font-weight: 700; } .fclk-pfab-stat-lbl { display: block; color: var(--pfab-muted); font-size: 9px; text-transform: uppercase; letter-spacing: 0.6px; margin-top: 2px; } .fclk-pfab-stat-divider { width: 1px; height: 28px; background: var(--pfab-divider); } /* ---- Action button ---- */ .fclk-pfab-action { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; border: none; border-radius: 12px; padding: 11px 0; font-size: 13px; font-weight: 600; cursor: pointer; transition: all 0.2s ease; letter-spacing: 0.3px; } .fclk-pfab-action .fa { font-size: 15px; } .fclk-pfab-action--in { background: linear-gradient(135deg, var(--pfab-teal) 0%, var(--pfab-blue) 100%); color: #fff; } .fclk-pfab-action--in:hover:not(:disabled) { box-shadow: 0 4px 16px rgba(13, 148, 136, 0.4); } .fclk-pfab-action--out { background: var(--pfab-red); color: #fff; } .fclk-pfab-action--out:hover:not(:disabled) { box-shadow: 0 4px 16px rgba(239, 68, 68, 0.35); } .fclk-pfab-action:disabled { opacity: 0.55; cursor: not-allowed; } /* ---- Error ---- */ .fclk-pfab-error { display: flex; align-items: flex-start; gap: 6px; color: var(--pfab-red); font-size: 11px; background: var(--pfab-error-bg); border-radius: 8px; padding: 8px 10px; margin-top: 10px; line-height: 1.4; } .fclk-pfab-error .fa { font-size: 12px; margin-top: 1px; flex-shrink: 0; } /* ---- Responsive: smaller screens ---- */ @media (max-width: 380px) { #fclk-portal-fab { bottom: 16px; left: 16px; } .fclk-pfab-panel { width: 260px; } } /* ============================================================ Employee portal — Payslips, 4-item nav, sign out (uses the --fclk-* palette above, so light/dark just works) ============================================================ */ /* Keep 4 nav items comfortable on narrow phones */ .fclk-nav-bar .fclk-nav-item { min-width: 64px; } /* Sign out (clock header, top-right) */ .fclk-header { position: relative; } .fclk-signout { position: absolute; top: 0; right: 0; display: inline-flex; align-items: center; justify-content: center; width: 38px; height: 38px; border-radius: 10px; color: var(--fclk-text-muted); background: var(--fclk-card); border: 1px solid var(--fclk-card-border); text-decoration: none; } .fclk-signout:hover { color: var(--fclk-text); } /* Payslip list rows (extend .fclk-report-item) */ .fclk-payslip-item { text-decoration: none; color: inherit; cursor: pointer; } .fclk-payslip-status { font-size: 12px; font-weight: 600; padding: 3px 10px; border-radius: 999px; white-space: nowrap; } .fclk-payslip-status--paid { background: var(--fclk-green-glow); color: var(--fclk-green); } .fclk-payslip-status--done { background: var(--fclk-hover-bg); color: var(--fclk-text-muted); } /* Payslip detail (inline paystub) */ .fclk-payslip-detail-header .fclk-payslip-back { display: inline-block; font-size: 13px; color: var(--fclk-green); text-decoration: none; margin-bottom: 6px; } .fclk-payslip-net { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; } .fclk-payslip-net-label { font-size: 13px; color: var(--fclk-text-muted); } .fclk-payslip-net-value { font-size: 26px; font-weight: 700; color: var(--fclk-green); } .fclk-payslip-section { margin-bottom: 16px; } .fclk-payslip-section-title { font-size: 13px; text-transform: uppercase; letter-spacing: .04em; color: var(--fclk-text-muted); margin: 0 0 10px; } .fclk-payslip-row { display: flex; align-items: center; justify-content: space-between; padding: 8px 0; font-size: 14px; color: var(--fclk-text); border-bottom: 1px solid var(--fclk-card-border); } .fclk-payslip-row:last-child { border-bottom: none; } .fclk-payslip-row--total { font-weight: 700; } .fclk-payslip-pdf-btn { display: flex; align-items: center; justify-content: center; width: 100%; padding: 14px; margin-bottom: 90px; /* clear the fixed bottom nav */ border-radius: 12px; background: var(--fclk-green); color: #fff; font-weight: 600; text-decoration: none; }