/* ============================================================ Elegant Work — Components CSS ============================================================ */ /* Add this to your components.css */ input[type="file"], input[type="text"], select, textarea { font-size: 16px !important; } /* ── Cards ──────────────────────────────────────────────── */ .card { background: var(--surface); border-radius: var(--radius); border: 1px solid var(--border); box-shadow: var(--shadow-sm); } .card-header { padding: 1.25rem 1.5rem; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; gap: 1rem; } .card-header h3, .card-header h4 { margin: 0; } .card-body { padding: 1.5rem; } .card-body-sm { padding: 1rem 1.5rem; } .card-footer { padding: 1rem 1.5rem; border-top: 1px solid var(--border); background: var(--bg); border-radius: 0 0 var(--radius) var(--radius); } /* ── Stat Cards ─────────────────────────────────────────── */ .stat-card { background: var(--surface); border-radius: var(--radius); border: 1px solid var(--border); padding: 1.25rem 1.5rem; display: flex; align-items: flex-start; gap: 1rem; box-shadow: var(--shadow-sm); transition: transform var(--duration) var(--ease), box-shadow var(--duration) var(--ease); } @media (max-width: 640px) { .stat-card { padding: .875rem 1rem; gap: .625rem; } .stat-icon-wrap { width: 36px; height: 36px; } .stat-value { font-size: 1.4rem; } .stat-label { font-size: .65rem; } } .stat-card:hover { transform: translateY(-2px); box-shadow: var(--shadow); } .stat-icon-wrap { width: 48px; height: 48px; border-radius: var(--radius); display: flex; align-items: center; justify-content: center; flex-shrink: 0; } .stat-label { font-size: .75rem; font-weight: 500; color: var(--text-muted); text-transform: uppercase; letter-spacing: .06em; margin-bottom: .25rem; } .stat-value { font-family: var(--font-display); font-size: 1.875rem; line-height: 1; color: var(--text); } .stat-change { font-size: .75rem; font-weight: 500; margin-top: .25rem; } .stat-change.up { color: var(--success); } .stat-change.down { color: var(--danger); } /* ── Buttons ────────────────────────────────────────────── */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: .5rem; padding: .5rem 1.125rem; border-radius: var(--radius-sm); font-family: var(--font-body); font-size: .875rem; font-weight: 500; line-height: 1; border: 1px solid transparent; transition: all var(--duration) var(--ease); cursor: pointer; white-space: nowrap; text-decoration: none; } .btn:disabled { opacity: .5; cursor: not-allowed; } .btn-primary { background: var(--primary); color: #fff; border-color: var(--primary); } .btn-primary:hover:not(:disabled) { background: var(--primary-light); border-color: var(--primary-light); box-shadow: 0 4px 12px rgba(27, 75, 138, .3); } .btn-secondary { background: var(--secondary); color: #fff; border-color: var(--secondary); } .btn-secondary:hover:not(:disabled) { background: var(--secondary-dark); box-shadow: 0 4px 12px rgba(240, 165, 0, .35); } .btn-outline { background: transparent; color: var(--primary); border-color: var(--primary); } .btn-outline:hover:not(:disabled) { background: var(--primary); color: #fff; } .btn-ghost { background: transparent; color: var(--text-muted); border-color: var(--border); } .btn-ghost:hover:not(:disabled) { background: var(--bg); color: var(--text); border-color: var(--border-dark); } .btn-danger { background: var(--danger); color: #fff; border-color: var(--danger); } .btn-danger:hover:not(:disabled) { background: #b91c1c; } .btn-success { background: var(--success); color: #fff; border-color: var(--success); } .btn-sm { padding: .375rem .75rem; font-size: .8rem; } .btn-lg { padding: .7rem 1.5rem; font-size: .9375rem; } .btn-icon { padding: .5rem; width: 36px; height: 36px; } .btn-icon-sm { padding: .3rem; width: 28px; height: 28px; } /* Loading spinner in btn */ .btn.loading .btn-text { opacity: 0; } .btn.loading::after { content: ''; position: absolute; width: 14px; height: 14px; border: 2px solid currentColor; border-top-color: transparent; border-radius: 50%; animation: spin .6s linear infinite; } .btn { position: relative; } @keyframes spin { to { transform: rotate(360deg); } } /* ── Forms ──────────────────────────────────────────────── */ .form-group { margin-bottom: 1.125rem; } .form-row { display: grid; gap: 1rem; } .form-row-2 { grid-template-columns: 1fr 1fr; } .form-row-3 { grid-template-columns: 1fr 1fr 1fr; } .form-label { display: block; font-size: .8125rem; font-weight: 500; color: var(--text); margin-bottom: .375rem; } .form-label .required { color: var(--danger); margin-left: .15rem; } .form-control { width: 100%; padding: .5625rem .875rem; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font-family: var(--font-body); font-size: .875rem; line-height: 1.5; transition: border-color var(--duration), box-shadow var(--duration); appearance: none; } .form-control:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(27, 75, 138, .12); } .form-control::placeholder { color: var(--text-light); } .form-control:disabled { background: var(--bg); color: var(--text-muted); cursor: not-allowed; } /* ── Mobile: prevent iOS auto-zoom on input focus ─────── */ @media (max-width: 768px) { input, select, textarea, .form-control { font-size: 16px !important; } } select.form-control { background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); background-repeat: no-repeat; background-position: right .625rem center; background-size: 1.25em; padding-right: 2.5rem; } textarea.form-control { resize: vertical; min-height: 100px; } .form-hint { font-size: .75rem; color: var(--text-muted); margin-top: .3rem; } .form-error { font-size: .75rem; color: var(--danger); margin-top: .3rem; } .form-control.is-invalid { border-color: var(--danger); } /* Search input */ .search-wrap { position: relative; } .search-wrap .form-control { padding-left: 2.25rem; } .search-wrap .search-icon { position: absolute; left: .75rem; top: 50%; transform: translateY(-50%); color: var(--text-muted); width: 15px; height: 15px; } /* ── Tables ─────────────────────────────────────────────── */ .table-wrap { overflow-x: auto; border-radius: var(--radius); border: 1px solid var(--border); } table { width: 100%; border-collapse: collapse; background: var(--surface); font-size: .875rem; } thead th { background: var(--bg); padding: .75rem 1rem; text-align: left; font-size: .7rem; font-weight: 600; color: var(--text-muted); text-transform: uppercase; letter-spacing: .07em; border-bottom: 1px solid var(--border); white-space: nowrap; } tbody td { padding: .875rem 1rem; border-bottom: 1px solid var(--border); color: var(--text); vertical-align: middle; } tbody tr:last-child td { border-bottom: none; } tbody tr:hover td { background: rgba(27, 75, 138, .03); } .td-mono { font-family: var(--font-mono); font-size: .8rem; color: var(--primary); } .td-bold { font-weight: 600; } /* ── Badges ─────────────────────────────────────────────── */ .badge { display: inline-flex; align-items: center; gap: .3rem; padding: .2em .65em; border-radius: 99px; font-size: .72rem; font-weight: 600; letter-spacing: .03em; white-space: nowrap; } .badge-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; } .badge-success { background: var(--success-bg); color: var(--success); } .badge-warning { background: var(--warning-bg); color: var(--warning); } .badge-danger { background: var(--danger-bg); color: var(--danger); } .badge-info { background: var(--info-bg); color: var(--info); } .badge-primary { background: rgba(27, 75, 138, .1); color: var(--primary); } .badge-muted { background: var(--bg); color: var(--text-muted); border: 1px solid var(--border); } .badge-secondary { background: rgba(240, 165, 0, .15); color: var(--secondary-dark); } /* ── Modal ──────────────────────────────────────────────── */ .modal-backdrop { position: fixed; inset: 0; background: rgba(0, 0, 0, .45); z-index: 1000; display: flex; align-items: center; justify-content: center; padding: 1rem; animation: fadeIn .15s var(--ease); backdrop-filter: blur(2px); } .modal { background: var(--surface); border-radius: var(--radius-lg); box-shadow: var(--shadow-xl); width: 100%; max-width: 560px; max-height: 90vh; overflow-y: auto; animation: modalIn .2s var(--ease); } .modal-lg { max-width: 760px; } .modal-xl { max-width: 980px; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes modalIn { from { opacity: 0; transform: scale(.95) translateY(10px); } to { opacity: 1; transform: scale(1) translateY(0); } } .modal-header { padding: 1.25rem 1.5rem; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; gap: 1rem; position: sticky; top: 0; background: var(--surface); z-index: 1; } .modal-title { font-size: 1rem; font-weight: 600; } .modal-close { color: var(--text-muted); background: none; border: none; padding: .25rem; display: flex; align-items: center; } .modal-close:hover { color: var(--text); } .modal-body { padding: 1.5rem; } .modal-footer { padding: 1rem 1.5rem; border-top: 1px solid var(--border); display: flex; align-items: center; justify-content: flex-end; gap: .75rem; background: var(--bg); border-radius: 0 0 var(--radius-lg) var(--radius-lg); } /* ── Pagination ─────────────────────────────────────────── */ .pagination { display: flex; align-items: center; gap: .5rem; padding: .875rem 1rem; border-top: 1px solid var(--border); font-size: .8rem; } .pagination-info { color: var(--text-muted); flex: 1; } .page-btn { width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font-size: .8rem; font-weight: 500; cursor: pointer; transition: all var(--duration); } .page-btn:hover, .page-btn.active { background: var(--primary); color: #fff; border-color: var(--primary); } .page-btn:disabled { opacity: .4; cursor: not-allowed; } /* ── Toast Notifications ────────────────────────────────── */ #toast-container { position: fixed; top: 1.25rem; right: 1.25rem; z-index: 9999; display: flex; flex-direction: column; gap: .5rem; pointer-events: none; } .toast { background: var(--surface); border-radius: var(--radius); box-shadow: var(--shadow-lg); padding: .875rem 1.25rem; display: flex; align-items: flex-start; gap: .75rem; min-width: 300px; max-width: 400px; border-left: 4px solid var(--primary); animation: toastIn .25s var(--ease) both; pointer-events: all; font-size: .875rem; } .toast.success { border-color: var(--success); } .toast.error { border-color: var(--danger); } .toast.warning { border-color: var(--warning); } .toast-icon { flex-shrink: 0; width: 18px; height: 18px; margin-top: 1px; } .toast-content { flex: 1; } .toast-title { font-weight: 600; color: var(--text); margin-bottom: .15rem; } .toast-msg { color: var(--text-muted); font-size: .8125rem; } .toast.hiding { animation: toastOut .2s var(--ease) both; } @keyframes toastIn { from { opacity: 0; transform: translateX(20px); } to { opacity: 1; transform: translateX(0); } } @keyframes toastOut { to { opacity: 0; transform: translateX(20px); } } /* ── Empty State ────────────────────────────────────────── */ .empty-state { text-align: center; padding: 3rem 1.5rem; color: var(--text-muted); } .empty-icon { width: 56px; height: 56px; background: var(--bg); border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; margin-bottom: 1rem; color: var(--text-light); } .empty-title { font-weight: 600; color: var(--text); margin-bottom: .5rem; font-size: .9375rem; } /* ── Loading ────────────────────────────────────────────── */ .loading-overlay { display: flex; align-items: center; justify-content: center; padding: 3rem; } .spinner { width: 32px; height: 32px; border: 3px solid var(--border); border-top-color: var(--primary); border-radius: 50%; animation: spin .7s linear infinite; } .skeleton { background: linear-gradient(90deg, var(--border) 25%, var(--bg) 50%, var(--border) 75%); background-size: 200% 100%; animation: shimmer 1.5s infinite; border-radius: var(--radius-sm); } @keyframes shimmer { to { background-position: -200% 0; } } /* ── Tabs ───────────────────────────────────────────────── */ .tabs-nav { display: flex; border-bottom: 2px solid var(--border); gap: 0; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; } .tabs-nav::-webkit-scrollbar { display: none; } .tabs-nav .tab-btn { flex-shrink: 0; } .tab-btn { padding: .75rem 1.25rem; border: none; background: none; color: var(--text-muted); font-family: var(--font-body); font-size: .875rem; font-weight: 500; cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -2px; transition: all var(--duration); white-space: nowrap; display: flex; align-items: center; gap: .5rem; } .tab-btn:hover { color: var(--text); } .tab-btn.active { color: var(--primary); border-bottom-color: var(--primary); } .tab-count { background: var(--bg); color: var(--text-muted); font-size: .7rem; font-weight: 600; padding: .1em .45em; border-radius: 99px; } .tab-btn.active .tab-count { background: rgba(27, 75, 138, .1); color: var(--primary); } .tab-pane { display: none; } .tab-pane.active { display: block; } /* ── Dropdown ───────────────────────────────────────────── */ .dropdown { position: relative; display: inline-block; } .dropdown-menu { position: absolute; top: calc(100% + .375rem); right: 0; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-lg); min-width: 180px; z-index: 500; animation: fadeIn .12s var(--ease); overflow: hidden; } .dropdown-item { display: flex; align-items: center; gap: .625rem; padding: .625rem 1rem; font-size: .875rem; color: var(--text); cursor: pointer; transition: background var(--duration); border: none; background: none; width: 100%; text-align: left; } .dropdown-item:hover { background: var(--bg); } .dropdown-item.danger { color: var(--danger); } .dropdown-divider { height: 1px; background: var(--border); margin: .25rem 0; } /* ── Priority & Status Colors ───────────────────────────── */ .priority-low { color: var(--text-muted); } .priority-medium { color: var(--info); } .priority-high { color: var(--warning); } .priority-critical, .priority-urgent, .priority-blocker { color: var(--danger); } /* ── Kanban Board ───────────────────────────────────────── */ .kanban-board { display: flex; gap: 1rem; overflow-x: auto; padding-bottom: .5rem; } .kanban-col { flex: 0 0 280px; background: var(--bg); border-radius: var(--radius); border: 1px solid var(--border); display: flex; flex-direction: column; max-height: calc(100vh - 200px); } .kanban-col-header { padding: .875rem 1rem; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; } .kanban-col-label { font-size: .8rem; font-weight: 600; text-transform: uppercase; letter-spacing: .06em; } .kanban-col-count { background: var(--surface); border: 1px solid var(--border); border-radius: 99px; font-size: .75rem; font-weight: 600; padding: .1em .5em; } .kanban-col-body { flex: 1; overflow-y: auto; padding: .75rem; display: flex; flex-direction: column; gap: .5rem; } .kanban-card { background: var(--surface); border-radius: var(--radius-sm); border: 1px solid var(--border); padding: .875rem 1rem; cursor: pointer; transition: all var(--duration); box-shadow: var(--shadow-sm); } .kanban-card:hover { box-shadow: var(--shadow); border-color: var(--primary); transform: translateY(-1px); } /* ── Timeline / Activity ────────────────────────────────── */ .timeline { display: flex; flex-direction: column; } .timeline-item { display: flex; gap: .875rem; padding-bottom: 1.25rem; position: relative; } .timeline-item:not(:last-child)::before { content: ''; position: absolute; left: 15px; top: 28px; bottom: 0; width: 1px; background: var(--border); } .timeline-dot { width: 34px; height: 34px; border-radius: 50%; background: var(--bg); border: 2px solid var(--border); display: flex; align-items: center; justify-content: center; flex-shrink: 0; z-index: 1; font-size: .95rem; line-height: 1; } .timeline-body { flex: 1; } .timeline-meta { font-size: .75rem; color: var(--text-muted); margin-top: .15rem; } /* ── Login Page ─────────────────────────────────────────── */ #login-screen { background: linear-gradient(135deg, var(--sidebar) 0%, var(--primary) 60%, #1a5fab 100%); display: flex; align-items: center; justify-content: center; padding: 1.5rem; position: relative; overflow: hidden; } #login-screen::before { content: ''; position: absolute; width: 600px; height: 600px; border-radius: 50%; background: rgba(255, 255, 255, .03); top: -200px; right: -100px; } #login-screen::after { content: ''; position: absolute; width: 400px; height: 400px; border-radius: 50%; background: rgba(240, 165, 0, .07); bottom: -100px; left: -100px; } .login-box { background: var(--surface); border-radius: var(--radius-xl); box-shadow: var(--shadow-xl); padding: 2.5rem; width: 100%; max-width: 420px; position: relative; z-index: 1; animation: modalIn .35s var(--ease) both; } .login-logo { display: flex; align-items: center; gap: .875rem; margin-bottom: 2rem; } .login-logo-mark { width: 44px; height: 44px; background: var(--primary); border-radius: 12px; display: flex; align-items: center; justify-content: center; font-family: var(--font-display); font-size: 1.25rem; color: #fff; box-shadow: 0 4px 16px rgba(27, 75, 138, .4); } .login-logo-text { font-family: var(--font-display); font-size: 1.25rem; color: var(--text); } .login-logo-sub { font-size: .7rem; font-weight: 500; color: var(--text-muted); text-transform: uppercase; letter-spacing: .1em; display: block; margin-top: -2px; } .login-title { font-size: 1.375rem; font-weight: 600; margin-bottom: .375rem; } .login-sub { color: var(--text-muted); font-size: .875rem; margin-bottom: 1.75rem; } .login-error { background: var(--danger-bg); border: 1px solid rgba(220, 38, 38, .2); border-radius: var(--radius-sm); padding: .75rem 1rem; color: var(--danger); font-size: .875rem; margin-bottom: 1rem; display: none; } /* ── Grid Layouts ───────────────────────────────────────── */ .grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.25rem; } .grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.25rem; } .grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.25rem; } @media (max-width: 1100px) { .grid-4 { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 900px) { .grid-3 { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 640px) { .grid-4 { grid-template-columns: repeat(2, 1fr); gap: .625rem; } .grid-3, .grid-2 { grid-template-columns: 1fr; } .form-row-2, .form-row-3 { grid-template-columns: 1fr; } } /* ── Two-column detail layout ───────────────────────────── */ /* ── Miscellaneous ──────────────────────────────────────── */ .divider { height: 1px; background: var(--border); margin: 1.25rem 0; } .avatar-group { display: flex; } .avatar-group .user-avatar { margin-left: -8px; border: 2px solid var(--surface); } .avatar-group .user-avatar:first-child { margin-left: 0; } .code { font-family: var(--font-mono); font-size: .8125rem; background: var(--bg); padding: .15em .4em; border-radius: 4px; color: var(--primary); } .filter-bar { display: flex; gap: .75rem; align-items: center; flex-wrap: wrap; margin-bottom: 1.25rem; } .filter-bar .search-wrap { flex: 1; min-width: 200px; } .section-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.25rem; } /* Severity badges */ .severity-trivial { background: var(--bg); color: var(--text-muted); border: 1px solid var(--border); } .severity-minor { background: var(--info-bg); color: var(--info); } .severity-major { background: var(--warning-bg); color: var(--warning); } .severity-critical { background: var(--danger-bg); color: var(--danger); } .severity-blocker { background: #18181b; color: #f87171; } /* Status colors mapping (utility classes) */ .status-active, .status-approved, .status-paid, .status-completed, .status-passed, .status-published, .status-in_stock { background: var(--success-bg); color: var(--success); } .status-planning, .status-pending, .status-open, .status-draft, .status-unlinked { background: var(--info-bg); color: var(--info); } .status-on_hold, .status-in_progress, .status-in_testing, .status-travelling, .status-on_site { background: var(--warning-bg); color: var(--warning); } .status-cancelled, .status-terminated, .status-rejected, .status-wont_fix, .status-inactive { background: var(--bg); color: var(--text-muted); } .status-no_charge { background: #f0fdf4; color: #15803d; } .status-internal_complete { background: #eff6ff; color: #1d4ed8; } .status-invoiced { background: #eff6ff; color: #1d4ed8; } .status-bugs_found, .status-suspended { background: var(--danger-bg); color: var(--danger); } /* ============================================================ CALENDAR ============================================================ */ .cal-shell { display: grid; grid-template-rows: auto auto 1fr; grid-template-columns: 1fr auto; grid-template-areas: "header header" "legend legend" "body panel"; gap: 0; min-height: calc(100vh - 120px); background: var(--surface); border-radius: var(--radius); border: 1px solid var(--border); overflow: hidden; } .cal-header { grid-area: header; display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: .75rem; padding: 1rem 1.25rem; border-bottom: 1px solid var(--border); background: var(--surface); } .cal-title { font-size: 1.1rem; font-weight: 600; min-width: 180px; text-align: center; } .cal-view-switcher { display: flex; border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; background: var(--bg); } .cal-view-switcher button { padding: .3rem .75rem; font-size: .8rem; font-weight: 500; border: none; background: none; cursor: pointer; color: var(--text-muted); transition: all .15s; } .cal-view-switcher button.active { background: var(--primary); color: #fff; } .cal-legend { grid-area: legend; display: flex; flex-wrap: wrap; gap: .5rem 1rem; padding: .5rem 1.25rem; border-bottom: 1px solid var(--border); background: var(--bg); } .cal-legend-item { display: flex; align-items: center; gap: .35rem; font-size: .7rem; color: var(--text-muted); } /* ── Month grid ─────────────────────────────────────────── */ .cal-body { grid-area: body; overflow: auto; background: var(--bg); } .cal-grid { display: flex; flex-direction: column; height: 100%; min-height: 500px; } .cal-day-headers { display: grid; grid-template-columns: repeat(7, 1fr); border-bottom: 1px solid var(--border); background: var(--surface); } .cal-day-header { padding: .4rem .5rem; font-size: .7rem; font-weight: 600; text-align: center; color: var(--text-muted); text-transform: uppercase; letter-spacing: .05em; } .cal-cells { display: grid; grid-template-columns: repeat(7, 1fr); flex: 1; } .cal-cell { border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); padding: .35rem .4rem; cursor: pointer; min-height: 90px; transition: background .1s; overflow: hidden; } .cal-cell:hover { background: var(--bg-hover, rgba(27, 75, 138, .04)); } .cal-cell:nth-child(7n) { border-right: none; } .cal-cell-other { background: var(--bg); opacity: .45; cursor: default; pointer-events: none; } .cal-cell-today .cal-cell-num { background: var(--primary); color: #fff; border-radius: 50%; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; } .cal-cell-selected { background: rgba(27, 75, 138, .06) !important; } .cal-cell-num { font-size: .78rem; font-weight: 600; color: var(--text); margin-bottom: .25rem; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; } .cal-cell-events { display: flex; flex-direction: column; gap: 2px; } .cal-event-pill { display: flex; align-items: center; gap: 3px; padding: 1px 5px; border-radius: 3px; font-size: .68rem; font-weight: 500; line-height: 1.4; overflow: hidden; white-space: nowrap; cursor: pointer; } .cal-pill-draggable { cursor: grab; } .cal-pill-draggable:active { cursor: grabbing; } .cal-cell-drop-over { background: rgba(27, 75, 138, .1) !important; outline: 2px dashed var(--primary); outline-offset: -2px; } .cal-event-time { font-weight: 600; flex-shrink: 0; } .cal-event-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .cal-more-pill { font-size: .68rem; color: var(--primary); font-weight: 600; padding: 1px 4px; cursor: pointer; } .cal-more-pill:hover { text-decoration: underline; } /* ── Day panel ──────────────────────────────────────────── */ .cal-day-panel { grid-area: panel; width: 280px; border-left: 1px solid var(--border); background: var(--surface); display: flex; flex-direction: column; gap: .5rem; padding: 1rem; overflow-y: auto; max-height: 700px; } .cal-day-panel-header { display: flex; align-items: center; justify-content: space-between; } .cal-day-panel-header h4 { font-size: .9rem; } /* ── List view ──────────────────────────────────────────── */ .cal-list { padding: 1rem; display: flex; flex-direction: column; gap: 1.5rem; } .cal-list-day {} .cal-list-date { font-size: .8rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--text-muted); margin-bottom: .5rem; padding-bottom: .25rem; border-bottom: 1px solid var(--border); } .cal-list-date.cal-list-today { color: var(--primary); } .cal-list-events { display: flex; flex-direction: column; gap: .5rem; } .cal-list-event { padding: .625rem .75rem; background: var(--bg); border-radius: var(--radius-sm); border-left: 3px solid var(--border); transition: transform .1s; } .cal-list-event:hover { transform: translateX(2px); } .cal-list-time { font-weight: 700; font-size: .78rem; margin-right: .35rem; color: var(--primary); } .cal-list-label { font-size: .85rem; font-weight: 500; } .cal-list-sub { font-size: .75rem; color: var(--text-muted); margin-top: .2rem; } /* ── Mobile responsive ──────────────────────────────────── */ @media (max-width: 768px) { .cal-shell { grid-template-areas: "header" "legend" "body" "panel"; grid-template-columns: 1fr; grid-template-rows: auto auto 1fr auto; } .cal-day-panel { width: 100%; border-left: none; border-top: 1px solid var(--border); max-height: 280px; } .cal-cell { min-height: 60px; padding: .2rem .25rem; } .cal-event-pill { display: none; } .cal-cell-events::after { /* Show dot indicators on mobile instead of pills */ content: ''; } /* On mobile show just a dot per event type */ .cal-cell[data-has-events="true"] .cal-cell-num::after { content: '•'; color: var(--primary); margin-left: 2px; font-size: .9rem; } .cal-legend { display: none; } .cal-header { padding: .75rem 1rem; } .cal-title { min-width: 140px; font-size: 1rem; } .cal-more-pill { display: block; } } @media (max-width: 480px) { .cal-day-header { font-size: .6rem; padding: .3rem .15rem; } .cal-cell-num { font-size: .72rem; width: 20px; height: 20px; } } /* ============================================================ JOB CARDS — Mobile-first v3 ============================================================ */ /* ── List: tech mobile cards ── */ /* ============================================================ JOB CARDS — List, mobile cards, tech view, admin view ============================================================ */ /* ── List card (tech mobile view) ── */ .jc-mobile-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; cursor: pointer; transition: box-shadow .15s, border-color .15s; -webkit-tap-highlight-color: transparent; } .jc-mobile-card:hover { border-color: var(--primary); box-shadow: 0 2px 8px rgba(0, 0, 0, .08); } .jc-mobile-card:active { opacity: .92; } .jc-mobile-card-header { display: flex; justify-content: space-between; align-items: flex-start; padding: .875rem 1rem; gap: .75rem; } .jc-mobile-card-header h4 { margin: .2rem 0 .25rem; font-size: .975rem; line-height: 1.3; } .jc-mobile-card-actions { padding: .625rem .875rem; border-top: 1px solid var(--border); background: var(--bg); display: flex; flex-direction: column; gap: .4rem; } /* ── Tech detail — mobile-first ── */ .jc-tech-view { max-width: 640px; margin: 0 auto; display: flex; flex-direction: column; gap: .75rem; padding-bottom: 2rem; width: 100%; box-sizing: border-box; } /* All direct children of tech view must be contained */ .jc-tech-view>* { width: 100%; max-width: 100%; box-sizing: border-box; min-width: 0; } .jc-tech-header { display: flex; align-items: flex-start; gap: .75rem; padding: 1rem; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; box-sizing: border-box; width: 100%; } .jc-tech-header>div { flex: 1; min-width: 0; } .jc-tech-header h4 { margin: 0 0 .2rem; font-size: 1.05rem; word-break: break-word; } /* ── Big action buttons ── */ .jc-big-action { width: 100%; padding: 1rem; font-size: 1rem; font-weight: 700; border-radius: var(--radius); display: flex; align-items: center; justify-content: center; gap: .625rem; border: none; cursor: pointer; transition: filter .12s, opacity .12s; } .jc-big-action:active { filter: brightness(.93); } /* ── Status progress bar ── */ .jc-status-card { padding: .75rem 1rem; overflow: hidden; } .jc-status-steps { display: flex; align-items: flex-start; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; gap: 0; padding: .25rem 0; width: 100%; box-sizing: border-box; } .jc-status-steps::-webkit-scrollbar { display: none; } .jc-status-step { display: flex; flex-direction: column; align-items: center; gap: .35rem; flex: 1; min-width: 40px; position: relative; } .jc-status-step:not(:last-child)::after { content: ''; position: absolute; top: 10px; left: calc(50% + 10px); right: calc(-50% + 10px); height: 2px; background: var(--border); z-index: 0; } .jc-status-step.done::after { background: var(--primary); } .jc-status-step.current::after { background: var(--border); } .jc-status-dot { width: 26px; height: 26px; border-radius: 50%; background: var(--bg); border: 2px solid var(--border); color: var(--text-muted); display: flex; align-items: center; justify-content: center; font-size: .68rem; font-weight: 700; position: relative; z-index: 1; transition: background .2s, border-color .2s, color .2s, box-shadow .2s; flex-shrink: 0; } .jc-status-step.done .jc-status-dot, .jc-status-dot.done { background: var(--primary); border-color: var(--primary); color: #fff; } .jc-status-step.current .jc-status-dot, .jc-status-dot.current { background: var(--primary); border-color: var(--primary); color: #fff; box-shadow: 0 0 0 4px rgba(27, 75, 138, .18); } .jc-status-label { font-size: .55rem; font-weight: 600; text-transform: uppercase; letter-spacing: .02em; color: var(--text-muted); text-align: center; white-space: normal; word-break: break-word; line-height: 1.2; max-width: 40px; } .jc-status-step.done .jc-status-label, .jc-status-step.current .jc-status-label { color: var(--primary); } /* ── Tech scrollable tab bar ── */ .jc-tech-tabs { display: grid; grid-template-columns: repeat(4, 1fr); gap: .2rem; padding: .2rem; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); width: 100%; box-sizing: border-box; } .jc-tech-tabs::-webkit-scrollbar { display: none; } .jc-tech-tabs button { padding: .45rem .4rem; border: none; background: none; border-radius: calc(var(--radius) - 2px); font-size: .75rem; font-weight: 500; color: var(--text-muted); cursor: pointer; display: flex; align-items: center; justify-content: center; gap: .25rem; transition: background .12s, color .12s; white-space: nowrap; -webkit-tap-highlight-color: transparent; width: 100%; text-align: center; } .jc-tech-tabs button:hover { background: var(--bg); color: var(--text); } .jc-tech-tabs button.active { background: var(--primary); color: #fff; } .jc-tab-badge { background: rgba(0, 0, 0, .12); color: inherit; border-radius: 999px; padding: .05rem .35rem; font-size: .63rem; font-weight: 700; line-height: 1.5; } .jc-tech-tabs button.active .jc-tab-badge { background: rgba(255, 255, 255, .28); } .jc-tab-badge.done { background: var(--success); color: #fff; } /* ── Tech tab pane ── */ .jc-tech-content { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; } .jc-tech-pane { display: none; padding: 1rem; } .jc-tech-pane.active { display: block; } /* ── Info grid (tech detail info tab) ── */ .info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: .875rem; } .info-item label { display: block; font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--text-muted); margin-bottom: .2rem; } .info-item p { font-size: .9rem; font-weight: 500; margin: 0; } /* ── Image grid ── */ .jc-images-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: .625rem; } .jc-image-card { position: relative; border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; background: var(--bg); } .jc-image-card img { width: 100%; height: 120px; object-fit: cover; cursor: pointer; display: block; } /* ── Checklist rows ── */ .checklist-row { display: flex; align-items: center; gap: .75rem; padding: .7rem .75rem; border: 1px solid var(--border); border-radius: var(--radius-sm); margin-bottom: .4rem; background: var(--surface); transition: background .12s, border-color .12s; min-height: 48px; } .checklist-row.checked { background: rgba(34, 197, 94, .04); border-color: rgba(34, 197, 94, .2); } .checklist-cb { width: 22px; height: 22px; flex-shrink: 0; cursor: pointer; accent-color: var(--primary); } .checklist-icon { font-size: 1rem; flex-shrink: 0; } .checklist-text { flex: 1; font-size: .9rem; line-height: 1.35; } .checklist-row.checked .checklist-text { text-decoration: line-through; color: var(--text-muted); } /* ── Signature canvas ── */ #sig-canvas { touch-action: none; background: #fff; } /* ============================================================ RESPONSIVE — Admin detail view ============================================================ */ /* Desktop: side-by-side, sidebar fixed width */ .detail-layout { display: grid; grid-template-columns: 1fr 280px; gap: 1.25rem; align-items: start; } .detail-layout>div:last-child { position: sticky; top: 1rem; } /* Tablet: single column, sidebar goes below */ @media (max-width: 1024px) { .detail-layout { grid-template-columns: 1fr; } } /* Tablet/Mobile: single column */ @media (max-width: 900px) { .detail-layout { display: flex !important; flex-direction: column !important; gap: .75rem !important; } .detail-layout>div, .detail-layout>div:last-child { min-width: 0 !important; width: 100% !important; } .detail-layout>div:last-child { order: -1; position: static !important; } /* Tab nav — horizontal scroll, no wrap */ .tabs-nav { overflow-x: auto !important; flex-wrap: nowrap !important; -webkit-overflow-scrolling: touch; scrollbar-width: none; } .tabs-nav::-webkit-scrollbar { display: none; } .tabs-nav .tab-btn { flex-shrink: 0; padding: .625rem .875rem; font-size: .82rem; } .tab-btn { flex-shrink: 0 !important; white-space: nowrap !important; } /* Status bar smaller on mobile */ .jc-status-label { font-size: .48rem; max-width: 36px; } .jc-status-dot { width: 20px; height: 20px; font-size: .55rem; } /* Contain all cards/tables within viewport — prevent page zoom */ .card, .table-wrap, .card-body, .card-body-sm { max-width: 100%; box-sizing: border-box; } /* Table wraps scroll internally, never cause page overflow */ .table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; } /* Filter bar stacks on mobile */ .filter-bar { flex-direction: column !important; align-items: stretch !important; } .filter-bar .search-wrap, .filter-bar select, .filter-bar input[type=date], .filter-bar .form-control { width: 100% !important; min-width: unset !important; max-width: 100% !important; flex: unset !important; } /* Section header — prevent overflow */ .section-header { flex-wrap: wrap; overflow: hidden; gap: .5rem; } .section-header>div:last-child { flex-wrap: wrap; } /* Info grid single col */ .info-grid { grid-template-columns: 1fr; } /* Images 2-col */ .jc-images-grid { grid-template-columns: repeat(2, 1fr); } /* Forms stack */ .form-row-2, .form-row-3 { grid-template-columns: 1fr !important; } /* Admin JC detail */ .jc-status-card { padding: .625rem .75rem; } } @media (max-width: 480px) { .jc-tech-header { padding: .875rem .75rem; gap: .5rem; } .jc-tech-header h3 { font-size: 1.05rem; } .jc-big-action { padding: 1rem; font-size: 1rem; border-radius: var(--radius); } .jc-tech-pane { padding: .875rem .75rem; font-size: .95rem; } .jc-tech-pane h5 { font-size: 1rem; } .jc-tech-pane label, .jc-tech-pane .form-label { font-size: .8rem; } .jc-tech-pane p, .jc-tech-pane .text-sm { font-size: .95rem; } .jc-images-grid { grid-template-columns: repeat(2, 1fr); } .section-header h3, .section-header h4 { font-size: 1rem; } /* Cards inside tech panes */ .jc-tech-pane .card { margin-bottom: .625rem; } /* Bigger checkboxes for touch */ .jc-tech-pane input[type=checkbox] { width: 20px; height: 20px; } /* Status steps more compact */ .jc-status-card { padding: .5rem .3rem; } /* ── Costing tab mobile fixes ── */ /* Invoice bar — 2×2 grid on mobile */ .costing-invoice-bar { display: grid !important; grid-template-columns: 1fr 1fr; gap: .625rem; padding: .75rem !important; } /* Whole costing wrap contained */ #jc-costing-wrap { overflow: hidden; max-width: 100%; box-sizing: border-box; } /* Costing tables — compact, no unit cost column */ #jc-costing-wrap table th:nth-child(3), #jc-costing-wrap table td:nth-child(3) { display: none; } #jc-costing-wrap table th, #jc-costing-wrap table td { padding: .4rem .5rem; font-size: .78rem; white-space: normal; word-break: break-word; } /* All d-flex rows inside costing — prevent children from overflowing */ #jc-costing-wrap .d-flex>span, #jc-costing-wrap .d-flex>div { min-width: 0; } /* Cards */ .card-body, .card-body-sm { padding: .75rem !important; } .card-header { padding: .625rem .75rem !important; } .card { border-radius: var(--radius-sm); } /* Page content */ .page-content { padding: .5rem !important; } /* Buttons slightly smaller */ .btn { font-size: .85rem; } /* Section headers — stack on mobile */ .section-header { flex-direction: column; align-items: flex-start; gap: .625rem; padding: 0 0 .5rem; margin-bottom: .625rem; } .section-header h3 { font-size: 1rem; } .section-header>div:last-child { width: 100%; } /* Tables inside cards */ tbody td, thead th { padding: .625rem .75rem; font-size: .8rem; } /* Form labels */ .form-label { font-size: .78rem; } /* Badges */ .badge { font-size: .65rem; padding: .15rem .4rem; } /* Modals */ .modal-content { margin: .5rem; max-height: calc(100vh - 1rem); border-radius: var(--radius); } .modal-header, .modal-footer { padding: .75rem 1rem; } .modal-body { padding: .875rem 1rem; } } /* ── Costing Invoice Bar ────────────────────────────────── */ .costing-invoice-bar { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: .75rem; padding: .875rem 1.25rem; } /* ── Search Dropdown (slip linking, etc.) ── */ .search-dropdown { position: absolute; z-index: 999; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow-lg); max-height: 220px; overflow-y: auto; width: 100%; margin-top: 2px; } .search-dropdown-item { padding: .5rem .75rem; font-size: .875rem; cursor: pointer; border-bottom: 1px solid var(--border); } .search-dropdown-item:last-child { border-bottom: none; } .search-dropdown-item:hover { background: var(--bg); } .form-group { position: relative; } /* ── Checklist Module ──────────────────────────────────── */ .tabs { display: flex; border-bottom: 2px solid var(--border); gap: 0; margin-bottom: 0; } .tabs .tab-btn { padding: .75rem 1.5rem; border: none; background: none; color: var(--text-muted); font-size: .875rem; font-weight: 500; cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -2px; transition: all var(--duration); white-space: nowrap; font-family: var(--font-body); } .tabs .tab-btn.active { color: var(--primary); border-bottom-color: var(--primary); font-weight: 600; } .tabs .tab-btn:hover:not(.active) { color: var(--text); background: var(--bg-secondary); } /* Checklist question builder row */ .cl-question-row:focus-within { box-shadow: 0 0 0 2px rgba(27, 75, 138, .15); border-color: var(--primary) !important; } /* Fill-in yes/no buttons */ .cl-yn-btn:hover { filter: brightness(.96); transform: translateY(-1px); } /* Justify end utility */ .justify-end { justify-content: flex-end; } /* ── Mobile: tabs horizontal scroll (checklists, etc.) ── */ @media (max-width: 768px) { .tabs { overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; flex-wrap: nowrap; } .tabs::-webkit-scrollbar { display: none; } .tabs .tab-btn { flex-shrink: 0; padding: .625rem 1rem; font-size: .82rem; } /* Module list pages — card items full width, readable */ .module-list-item { padding: .875rem 1rem; border-bottom: 1px solid var(--border); } /* Settings form — single column on mobile */ #settings-body .form-row-2 { grid-template-columns: 1fr !important; } /* Fleet grid — single column on very small screens */ #fleet-body>div[style*="grid"] { grid-template-columns: 1fr !important; } /* Employee/client detail pages — info grids stack */ .detail-layout .form-row-2 { grid-template-columns: 1fr !important; } /* Any page header with action buttons wraps cleanly */ .section-header .d-flex { flex-wrap: wrap; gap: .5rem; } /* Checklist template cards — full width stack */ .cl-template-grid, [class*="cl-grid"] { grid-template-columns: 1fr !important; } } /* ── Calendar overdue ──────────────────────────────────── */ .cal-pill-overdue { animation: cal-pulse 2s ease-in-out infinite; } @keyframes cal-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .75; } }