diff --git a/backend/controllers/csvDownload.controller.js b/backend/controllers/csvDownload.controller.js index 45dc6f1..e440efe 100644 --- a/backend/controllers/csvDownload.controller.js +++ b/backend/controllers/csvDownload.controller.js @@ -78,17 +78,23 @@ async function downloadData(req, res) { try { const data = await getAllTasksWithSubjects(); + const escapeCsv = (val) => { + const str = String(val ?? ''); + const escaped = /[,"\n\r]/.test(str) ? `"${str.replace(/"/g, '""')}"` : str; + return /^[=+\-@]/.test(escaped) ? `'${escaped}` : escaped; + }; + const rows = [ ['Task ID', 'Subject', 'Title', 'Due At', 'Status', 'Priority', 'Confidence Score', 'Notes'], ...data.map(task => [ task.id, - task.subject_name, - task.title, - task.due_at, - task.status, - task.priority, + escapeCsv(task.subject_name), + escapeCsv(task.title), + escapeCsv(task.due_at), + escapeCsv(task.status), + escapeCsv(task.priority), task.confidence_score, - `"${(task.notes || '').replace(/"/g, '""')}"`, + escapeCsv(task.notes), ]), ]; diff --git a/css/index.css b/css/index.css index f5561bd..212bfad 100644 --- a/css/index.css +++ b/css/index.css @@ -156,6 +156,7 @@ body { display: flex; flex-direction: column; gap: 4px; + overflow-y: auto; } .sidebar-header { @@ -185,7 +186,6 @@ body { .nav-item:hover { background: var(--color-background-primary); color: var(--color-text-primary); - transform: translateX(2px); } .nav-item.active { @@ -221,12 +221,13 @@ body { color: var(--color-text-secondary); padding: 2px 8px; border-radius: 12px; - transition: all 0.2s; + border: 1px solid transparent; + transition: background 0.2s, color 0.2s; } .nav-item:hover .badge { background: var(--color-background-primary); - border: 1px solid var(--color-border-tertiary); + border-color: var(--color-border-tertiary); } .sidebar-divider { @@ -853,6 +854,7 @@ body { overflow: hidden; width: 48px; min-width: 48px; + max-width: 48px; } .panel.panel-collapsed .panel-title, @@ -860,8 +862,15 @@ body { .panel.panel-collapsed .paste-zone, .panel.panel-collapsed .paste-actions, .panel.panel-collapsed .extract-preview, -.panel.panel-collapsed .add-btn { - display: none; +.panel.panel-collapsed .add-btn, +.panel.panel-collapsed .summary-box { + display: none !important; +} + +.panel.panel-collapsed .panel-header { + padding: 12px; + justify-content: center; + border-bottom: none; } .panel-header { @@ -1536,13 +1545,13 @@ body { #new-subject-modal .modal-card { width: 100%; max-width: 360px; - background-color: #0f172a; + background: var(--color-background-primary); border-radius: 14px; padding: 20px 20px 16px; - box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6) !important; - color: #e5e7eb; + box-shadow: var(--shadow-lg); + color: var(--color-text-primary); box-sizing: border-box; - border: 1px solid rgba(148, 163, 184, 0.35) !important; + border: 1px solid var(--color-border-secondary); } @@ -1552,7 +1561,7 @@ body { font-size: 18px; font-weight: 600; letter-spacing: 0.01em; - color: #f9fafb; + color: var(--color-text-primary); } @@ -1563,8 +1572,7 @@ body { font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; - color: #9ca3af; - /* muted */ + color: var(--color-text-tertiary); margin-bottom: 4px; } @@ -1579,17 +1587,16 @@ body { padding: 7px 8px; margin-bottom: 10px; border-radius: 6px; - border: 1px solid #4b5563; - background-color: #111827 !important; - color: #e5e7eb; + border: 1px solid var(--color-border-secondary); + background: var(--color-background-secondary); + color: var(--color-text-primary); transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease; - color-scheme: dark; } #new-task-modal input::placeholder, #new-subject-modal input::placeholder { - color: #6b7280; + color: var(--color-text-tertiary); } @@ -1600,7 +1607,7 @@ body { outline: none; border-color: #4f46e5; box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.35); - background: #020617; + background: var(--color-background-tertiary); } @@ -1685,3284 +1692,3 @@ body { #new-subject-modal .subject-color-swatch--selected { box-shadow: 0 0 0 2px #0f172a, 0 0 0 4px #a5b4fc; } - -/* css/index.css */ -*, -*::before, -*::after { - box-sizing: border-box; - margin: 0; - padding: 0; -} - -:root { - --color-background-primary: #ffffff; - --color-background-secondary: #f7f7f5; - --color-background-tertiary: #efefec; - --color-text-primary: #1a1a18; - --color-text-secondary: #6b6b66; - --color-text-tertiary: #9c9a92; - --color-border-tertiary: rgba(0, 0, 0, 0.08); - /* softer */ - --color-border-secondary: rgba(0, 0, 0, 0.15); - /* softer */ - --color-border-primary: rgba(0, 0, 0, 0.30); - - --color-danger-rgb: 163, 45, 45; - --color-info-rgb: 24, 95, 165; - --color-success-rgb: 22, 101, 52; - - --color-text-danger: #a32d2d; - --color-background-danger: #fcebeb; - --color-border-danger: rgba(var(--color-danger-rgb), 0.35); - - --color-text-info: #185fa5; - --color-background-info: #e6f1fb; - --color-border-info: rgba(var(--color-info-rgb), 0.35); - - --color-text-success: #166534; - --color-background-success: #eaf3de; - --color-border-success: rgba(var(--color-success-rgb), 0.35); - - --color-text-warning: #854f0b; - --color-background-warning: #faeeda; - - --color-text-purple: #3c3489; - --color-background-purple: #eeedfe; - - --border-radius-sm: 6px; - --border-radius-md: 10px; - --border-radius-lg: 16px; - --font-sans: 'Inter', system-ui, -apple-system, sans-serif; - - --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.04); - --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.06); - --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.08); -} - -@media (prefers-color-scheme: dark) { - :root { - --color-background-primary: #181816; - --color-background-secondary: #20201e; - --color-background-tertiary: #272725; - --color-text-primary: #efede5; - --color-text-secondary: #a3a198; - --color-text-tertiary: #73726c; - --color-border-tertiary: rgba(255, 255, 255, 0.06); - --color-border-secondary: rgba(255, 255, 255, 0.12); - --color-border-primary: rgba(255, 255, 255, 0.22); - --color-text-danger: #fc9c9c; - --color-background-danger: rgba(252, 156, 156, 0.15); - --color-border-danger: rgba(252, 156, 156, 0.3); - - --color-text-info: #9ecdfc; - --color-background-info: rgba(158, 205, 252, 0.15); - --color-border-info: rgba(158, 205, 252, 0.3); - - --color-text-success: #a0d45a; - --color-background-success: rgba(160, 212, 90, 0.15); - --color-border-success: rgba(160, 212, 90, 0.3); - - --color-text-warning: #fab35e; - --color-background-warning: rgba(250, 179, 94, 0.15); - - --color-text-purple: #b9b5f5; - --color-background-purple: rgba(185, 181, 245, 0.15); - } -} - -:root[data-theme="dark"] { - --color-background-primary: #181816; - --color-background-secondary: #20201e; - --color-background-tertiary: #272725; - --color-text-primary: #efede5; - --color-text-secondary: #a3a198; - --color-text-tertiary: #73726c; - --color-border-tertiary: rgba(255, 255, 255, 0.06); - --color-border-secondary: rgba(255, 255, 255, 0.12); - --color-border-primary: rgba(255, 255, 255, 0.22); - --color-text-danger: #fc9c9c; - --color-background-danger: rgba(252, 156, 156, 0.15); - --color-border-danger: rgba(252, 156, 156, 0.3); - - --color-text-info: #9ecdfc; - --color-background-info: rgba(158, 205, 252, 0.15); - --color-border-info: rgba(158, 205, 252, 0.3); - - --color-text-success: #a0d45a; - --color-background-success: rgba(160, 212, 90, 0.15); - --color-border-success: rgba(160, 212, 90, 0.3); - - --color-text-warning: #fab35e; - --color-background-warning: rgba(250, 179, 94, 0.15); - - --color-text-purple: #b9b5f5; - --color-background-purple: rgba(185, 181, 245, 0.15); -} - -:root[data-theme="light"] { - --color-background-primary: #ffffff; - --color-background-secondary: #f7f7f5; - --color-background-tertiary: #efefec; - --color-text-primary: #1a1a18; - --color-text-secondary: #6b6b66; - --color-text-tertiary: #9c9a92; - --color-border-tertiary: rgba(0, 0, 0, 0.08); - --color-border-secondary: rgba(0, 0, 0, 0.15); - --color-border-primary: rgba(0, 0, 0, 0.30); - - --color-text-danger: #a32d2d; - --color-background-danger: #fcebeb; - --color-border-danger: rgba(163, 45, 45, 0.35); - - --color-text-info: #185fa5; - --color-background-info: #e6f1fb; - --color-border-info: rgba(24, 95, 165, 0.35); - - --color-text-success: #166534; - --color-background-success: #eaf3de; - --color-border-success: rgba(22, 101, 52, 0.35); - - --color-text-warning: #854f0b; - --color-background-warning: #faeeda; - - --color-text-purple: #3c3489; - --color-background-purple: #eeedfe; -} - -body { - font-family: var(--font-sans); - background: var(--color-background-tertiary); - color: var(--color-text-primary); - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 32px 16px; - overflow-x: hidden; -} - -/* Animations */ -@keyframes fadeIn { - from { - opacity: 0; - transform: translateY(5px); - } - - to { - opacity: 1; - transform: translateY(0); - } -} - -@keyframes popIn { - 0% { - transform: scale(0.95); - opacity: 0; - } - - 100% { - transform: scale(1); - opacity: 1; - } -} - -.wrapper { - width: 100%; - max-width: 1200px; - animation: fadeIn 0.6s cubic-bezier(0.16, 1, 0.3, 1); -} - -.label { - font-size: 12px; - font-weight: 600; - color: var(--color-text-tertiary); - letter-spacing: .08em; - margin-bottom: 12px; - text-transform: uppercase; -} - -.app { - display: grid; - grid-template-columns: 240px 1fr 340px; - height: 720px; - border: 1px solid var(--color-border-tertiary); - border-radius: var(--border-radius-lg); - overflow: hidden; - background: var(--color-background-primary); - box-shadow: var(--shadow-lg); - backdrop-filter: blur(20px); -} - -/* Sidebar */ -.sidebar { - background: var(--color-background-secondary); - border-right: 1px solid var(--color-border-tertiary); - padding: 20px 16px; - display: flex; - flex-direction: column; - gap: 4px; -} - -.sidebar-header { - font-size: 11px; - font-weight: 700; - color: var(--color-text-tertiary); - padding: 8px 12px; - margin-bottom: 2px; - letter-spacing: .06em; - text-transform: uppercase; -} - -.nav-item { - display: flex; - align-items: center; - gap: 12px; - padding: 10px 12px; - border-radius: var(--border-radius-md); - cursor: pointer; - font-size: 14px; - font-weight: 500; - color: var(--color-text-secondary); - transition: all 0.2s ease; - position: relative; -} - -.nav-item:hover { - background: var(--color-background-primary); - color: var(--color-text-primary); - transform: translateX(2px); -} - -.nav-item.active { - background: var(--color-background-primary); - color: var(--color-text-primary); - box-shadow: var(--shadow-sm); -} - -.nav-item.active::before { - content: ''; - position: absolute; - left: 0; - top: 15%; - height: 70%; - width: 3px; - background: var(--color-text-primary); - border-radius: 4px; -} - -.nav-dot { - width: 10px; - height: 10px; - border-radius: 50%; - flex-shrink: 0; - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1); -} - -.badge { - margin-left: auto; - font-size: 12px; - font-weight: 600; - background: var(--color-background-tertiary); - color: var(--color-text-secondary); - padding: 2px 8px; - border-radius: 12px; - transition: all 0.2s; -} - -.nav-item:hover .badge { - background: var(--color-background-primary); - border: 1px solid var(--color-border-tertiary); -} - -.sidebar-divider { - height: 1px; - background: var(--color-border-tertiary); - margin: 12px 0; -} - -.add-subject { - font-size: 13px; - font-weight: 500; - color: var(--color-text-tertiary); - padding: 8px 12px; - cursor: pointer; - transition: color 0.2s; - display: flex; - align-items: center; - gap: 8px; -} - -.add-subject:hover { - color: var(--color-text-primary); -} - -/* Main */ -.main { - display: flex; - flex-direction: column; - overflow: hidden; - position: relative; -} - -.topbar { - display: flex; - align-items: center; - gap: 12px; - padding: 16px 24px; - border-bottom: 1px solid var(--color-border-tertiary); - flex-shrink: 0; - background: rgba(var(--color-background-primary), 0.8); - backdrop-filter: blur(10px); - z-index: 10; -} - -.topbar-title { - font-size: 18px; - font-weight: 600; - color: var(--color-text-primary); - flex: 1; -} - -.btn { - font-family: inherit; - font-size: 13px; - font-weight: 600; - padding: 8px 16px; - border: 1px solid var(--color-border-secondary); - border-radius: var(--border-radius-sm); - background: var(--color-background-primary); - color: var(--color-text-primary); - cursor: pointer; - transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); - box-shadow: var(--shadow-sm); - display: inline-flex; - align-items: center; - justify-content: center; - gap: 6px; -} - -.btn:hover { - background: var(--color-background-secondary); - transform: translateY(-1px); - box-shadow: var(--shadow-md); -} - -.btn:active { - transform: translateY(0); - box-shadow: 0 0 0; -} - -.btn-primary { - background: var(--color-text-primary); - color: var(--color-background-primary); - border-color: transparent; -} - -.btn-primary:hover { - background: var(--color-text-secondary); -} - -/* Calendar */ -.cal-section { - padding: 16px 24px; - border-bottom: 1px solid var(--color-border-tertiary); - flex-shrink: 0; -} - -.cal-header { - display: flex; - align-items: center; - margin-bottom: 16px; -} - -.cal-title { - font-size: 15px; - font-weight: 600; - flex: 1; - color: var(--color-text-primary); -} - -.cal-nav { - font-size: 18px; - color: var(--color-text-secondary); - cursor: pointer; - padding: 4px 8px; - border-radius: 4px; - transition: background 0.2s; -} - -.cal-nav:hover { - background: var(--color-background-secondary); - color: var(--color-text-primary); -} - -.cal-grid { - display: grid; - grid-template-columns: repeat(7, 1fr); - gap: 4px; - text-align: center; -} - -.cal-day-label { - font-size: 11px; - color: var(--color-text-tertiary); - padding-bottom: 8px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.05em; -} - -.cal-day { - font-size: 13px; - font-weight: 500; - height: 32px; - display: flex; - align-items: center; - justify-content: center; - border-radius: var(--border-radius-md); - cursor: pointer; - color: var(--color-text-secondary); - position: relative; - transition: all 0.2s; -} - -.cal-day:hover { - background: var(--color-background-secondary); - color: var(--color-text-primary); - transform: scale(1.1); - z-index: 1; -} - -.cal-day.today { - background: var(--color-text-primary); - color: var(--color-background-primary); - box-shadow: var(--shadow-sm); -} - -.cal-day-indicators { - position: absolute; - bottom: 3px; - left: 0; - right: 0; - display: flex; - justify-content: center; - gap: 3px; -} - -.cal-day-indicator { - width: 5px; - height: 5px; - border-radius: 50%; -} - -.cal-day.muted { - color: var(--color-border-secondary); -} - -.cal-legend { - display: flex; - gap: 16px; - margin-top: 16px; - font-size: 11px; - font-weight: 500; - color: var(--color-text-tertiary); - justify-content: flex-end; -} - -.cal-legend span { - display: flex; - align-items: center; - gap: 6px; -} - -.legend-dot { - width: 8px; - height: 8px; - border-radius: 50%; - display: inline-block; -} - -/* Tasks */ -.tasks-section { - flex: 1; - overflow-y: auto; - padding: 0 24px 24px; - scroll-behavior: smooth; -} - -.tasks-section::-webkit-scrollbar { - width: 6px; -} - -.tasks-section::-webkit-scrollbar-thumb { - background: var(--color-border-secondary); - border-radius: 10px; -} - -.tasks-actions-bar { - margin-top: 18px; - display: flex; - gap: 10px; - flex-wrap: wrap; -} - -.task-action-btn { - border: 1px solid var(--color-border-success); - background: var(--color-background-success); - color: var(--color-text-success); - border-radius: var(--border-radius-sm); - padding: 7px 12px; - font-size: 12px; - font-weight: 700; - cursor: pointer; - transition: all 0.2s ease; -} - -.task-action-btn:hover { - filter: brightness(0.98); - transform: translateY(-1px); -} - -.task-action-btn:disabled { - opacity: 0.55; - cursor: not-allowed; - transform: none; - filter: none; -} - -.task-action-btn-secondary { - border-color: var(--color-border-info); - background: var(--color-background-info); - color: var(--color-text-info); -} - -.tasks-empty-state { - margin-top: 14px; - padding: 14px; - border-radius: var(--border-radius-md); - border: 1px dashed var(--color-border-secondary); - color: var(--color-text-secondary); - font-size: 13px; - background: var(--color-background-secondary); -} - -.tasks-group { - margin-top: 24px; - animation: fadeIn 0.4s ease forwards; -} - -.tasks-group-header { - display: flex; - align-items: center; - gap: 8px; - margin-bottom: 12px; -} - -.tasks-group-header span { - font-size: 12px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.05em; -} - -.task-item { - display: flex; - align-items: flex-start; - gap: 14px; - padding: 12px 14px; - border-radius: var(--border-radius-md); - cursor: pointer; - transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); - border: 1px solid transparent; - background: var(--color-background-primary); - margin-bottom: 6px; - border: 1px solid var(--color-border-tertiary); -} - -.task-item:hover { - background: var(--color-background-secondary); - transform: translateX(4px); - border-color: var(--color-border-secondary); - box-shadow: var(--shadow-sm); -} - -.task-item.urgent { - border-color: var(--color-border-danger); - background: linear-gradient(to right, var(--color-background-danger) 0%, var(--color-background-primary) 100%); -} - -.task-check { - width: 18px; - height: 18px; - border-radius: 5px; - border: 2px solid var(--color-border-secondary); - flex-shrink: 0; - margin-top: 2px; - transition: all 0.2s; - position: relative; - cursor: pointer; -} - -.task-check:hover { - border-color: var(--color-text-primary); -} - -.task-check.done { - background: var(--color-text-success); - border-color: var(--color-text-success); -} - -.task-check.done::after { - content: ''; - position: absolute; - left: 4px; - top: 1px; - width: 4px; - height: 8px; - border: solid white; - border-width: 0 2px 2px 0; - transform: rotate(45deg); -} - -.task-info { - flex: 1; - min-width: 0; -} - -.task-name { - font-size: 14px; - font-weight: 500; - color: var(--color-text-primary); - line-height: 1.4; - transition: color 0.2s; - margin-bottom: 6px; -} - -.task-item.done .task-name { - text-decoration: line-through; - color: var(--color-text-tertiary); -} - -.task-meta { - font-size: 12px; - color: var(--color-text-tertiary); - margin-top: 6px; - display: flex; - gap: 8px; - flex-wrap: wrap; - align-items: center; - font-weight: 500; -} - -.task-pill { - font-size: 11px; - padding: 2px 8px; - border-radius: 12px; - font-weight: 600; - display: inline-flex; - align-items: center; - gap: 4px; - border: 1px solid transparent; -} - -.pill-red { - background: var(--color-background-danger); - color: var(--color-text-danger); - border-color: var(--color-border-danger); -} - -.pill-blue { - background: var(--color-background-info); - color: var(--color-text-info); - border-color: var(--color-border-info); -} - -.pill-green { - background: var(--color-background-success); - color: var(--color-text-success); - border-color: var(--color-border-success); -} - -.pill-amber { - background: var(--color-background-warning); - color: var(--color-text-warning); - border-color: rgba(133, 79, 11, 0.2); -} - -.pill-purple { - background: var(--color-background-purple); - color: var(--color-text-purple); - border-color: rgba(60, 52, 137, 0.2); -} - -.conflict-card { - font-size: 13px; - font-weight: 500; - color: var(--color-text-warning); - background: var(--color-background-warning); - border: 1px solid rgba(133, 79, 11, 0.3); - border-radius: var(--border-radius-md); - padding: 12px 16px; - line-height: 1.5; - display: flex; - gap: 12px; - align-items: flex-start; - box-shadow: var(--shadow-sm); -} - -.conflict-icon { - font-size: 18px; - line-height: 1; -} - -.task-actions { - display: flex; - gap: 8px; - opacity: 0; - transition: opacity 0.2s; -} - -.task-item:hover .task-actions { - opacity: 1; -} - -.task-btn { - padding: 4px 8px; - border-radius: 4px; - font-size: 11px; - font-weight: 600; - cursor: pointer; - border: 1px solid var(--color-border-secondary); - background: var(--color-background-primary); - color: var(--color-text-secondary); - transition: all 0.2s; -} - -.task-btn:hover { - background: var(--color-background-secondary); - color: var(--color-text-primary); - border-color: var(--color-border-primary); -} - -.task-btn-danger:hover { - background: var(--color-background-danger); - color: var(--color-text-danger); - border-color: var(--color-text-danger); -} - -.task-btn-info:hover { - background: var(--color-background-info); - color: var(--color-text-info); - border-color: var(--color-text-info); -} - -/* Right Panel */ -.panel { - border-left: 1px solid var(--color-border-tertiary); - display: flex; - flex-direction: column; - background: var(--color-background-secondary); - overflow: hidden; -} - -.panel-header { - padding: 20px 24px 16px; - border-bottom: 1px solid var(--color-border-tertiary); - background: var(--color-background-primary); - flex-shrink: 0; -} - -.panel-title { - font-size: 16px; - font-weight: 600; - color: var(--color-text-primary); - display: flex; - align-items: center; - gap: 8px; -} - -.panel-title svg { - opacity: 0.8; -} - -.panel-subtitle { - font-size: 12px; - font-weight: 500; - color: var(--color-text-tertiary); - margin-top: 4px; -} - -.paste-zone { - margin: 20px 20px 12px; - border: 2px dashed var(--color-border-secondary); - border-radius: var(--border-radius-lg); - padding: 24px 20px; - text-align: center; - cursor: text; - transition: all 0.2s; - background: var(--color-background-primary); - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - position: relative; - min-height: 120px; - overflow: hidden; -} - -.paste-zone:hover { - border-color: var(--color-text-info); - background: var(--color-background-info); -} - -.paste-zone:focus-within { - border-color: var(--color-text-primary); - border-style: solid; - box-shadow: inset 0 0 0 1px var(--color-text-primary); - outline: none; -} - -.paste-icon { - font-size: 24px; - margin-bottom: 8px; - color: var(--color-text-secondary); - transition: color 0.2s; -} - -.paste-zone:hover .paste-icon { - color: var(--color-text-info); -} - -.paste-input { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - width: 100%; - height: 100%; - opacity: 0; - resize: none; - border: none; - padding: 20px; - font-family: inherit; - font-size: 13px; - z-index: 2; -} - -.summary-box { - margin: 0 20px 16px; - padding: 14px; - background: linear-gradient(135deg, #eef2ff, #f8fafc); - border-radius: 12px; - font-size: 14px; - line-height: 1.6; - border: 1px solid #e5e7eb; - flex-shrink: 0; - overflow-y: auto; - max-height: 200px; -} - -.paste-input:focus, -.paste-input:not(:placeholder-shown) { - opacity: 1; - z-index: 10; - background: var(--color-background-primary); - color: var(--color-text-primary); - outline: none; -} - -.paste-label { - font-size: 14px; - font-weight: 600; - color: var(--color-text-primary); - margin-bottom: 4px; - pointer-events: none; -} - -.paste-hint { - font-size: 12px; - color: var(--color-text-tertiary); - line-height: 1.5; - pointer-events: none; -} - -.paste-actions { - padding: 0 20px 16px; - display: flex; - gap: 12px; -} - -.extract-preview { - overflow-y: auto; - padding: 0 20px 12px; - scroll-behavior: smooth; - max-height: 280px; -} - -.extract-preview::-webkit-scrollbar { - width: 6px; -} - -.extract-preview::-webkit-scrollbar-thumb { - background: var(--color-border-secondary); - border-radius: 10px; -} - -.extract-title { - font-size: 11px; - font-weight: 700; - color: var(--color-text-tertiary); - margin-bottom: 12px; - letter-spacing: .06em; - text-transform: uppercase; - display: flex; - align-items: center; - justify-content: space-between; -} - -.extract-card { - background: var(--color-background-primary); - border: 1px solid var(--color-border-tertiary); - border-radius: var(--border-radius-md); - padding: 14px 16px; - margin-bottom: 12px; - box-shadow: var(--shadow-sm); - animation: popIn 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; - transform-origin: center; - position: relative; - overflow: hidden; -} - -.extract-subject { - font-size: 11px; - font-weight: 700; - margin-bottom: 6px; - letter-spacing: .04em; - text-transform: uppercase; -} - -.extract-task-name { - font-size: 14px; - font-weight: 600; - color: var(--color-text-primary); - margin-bottom: 8px; - line-height: 1.4; -} - -.extract-row { - display: flex; - align-items: center; - gap: 8px; - font-size: 12px; - font-weight: 500; - color: var(--color-text-secondary); - margin-top: 4px; -} - -.extract-icon { - font-size: 14px; -} - -.conf-bar { - height: 4px; - border-radius: 2px; - margin-top: 12px; - background: var(--color-border-tertiary); - overflow: hidden; -} - -.conf-fill { - height: 100%; - border-radius: 2px; - transition: width 1s cubic-bezier(0.16, 1, 0.3, 1); -} - -.conf-label { - font-size: 11px; - font-weight: 600; - color: var(--color-text-tertiary); - margin-top: 6px; - display: flex; - justify-content: space-between; -} - -.conf-edit { - color: var(--color-text-info); - cursor: pointer; - transition: color 0.2s; -} - -.conf-edit:hover { - color: var(--color-text-primary); -} - -.add-btn { - margin: 0 20px 20px; - padding: 12px; - border: none; - border-radius: var(--border-radius-md); - background: var(--color-text-primary); - color: var(--color-background-primary); - font-size: 14px; - font-weight: 600; - cursor: pointer; - text-align: center; - flex-shrink: 0; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); - transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); -} - -.add-btn:hover:not(:disabled) { - background: var(--color-text-secondary); - transform: translateY(-2px); - box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2); -} - -.add-btn:active:not(:disabled) { - transform: translateY(0); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); -} - -.add-btn:disabled { - background: var(--color-border-secondary); - cursor: not-allowed; - transform: none; - box-shadow: none; - color: var(--color-text-tertiary); -} - -/* Loader */ -.loader-spinner { - display: inline-block; - width: 16px; - height: 16px; - border: 2px solid rgba(0, 0, 0, 0.1); - border-radius: 50%; - border-top-color: var(--color-text-primary); - animation: spin 0.8s linear infinite; -} - -@media (prefers-color-scheme: dark) { - .loader-spinner { - border-color: rgba(255, 255, 255, 0.1); - border-top-color: #fff; - } -} - -@keyframes spin { - to { - transform: rotate(360deg); - } -} - -/* Utility classes */ -.hidden { - display: none !important; -} - - - -/* Header */ -.site-header { - width: 100%; - max-width: 1200px; - margin: 0 auto 16px auto; - padding: 16px 24px; - background: var(--color-background-primary); - border: 1px solid var(--color-border-tertiary); - border-radius: var(--border-radius-lg); - box-shadow: var(--shadow-md); - - display: flex; - align-items: center; - justify-content: space-between; -} - -.header-left { - display: flex; - align-items: center; - gap: 12px; -} - -.logo { - width: 40px; - height: 40px; - border-radius: 2px; -} - -.site-title { - font-size: 20px; - font-weight: 700; - color: var(--color-text-primary); -} - -.header-nav { - display: flex; - gap: 24px; -} - -.header-nav a { - text-decoration: none; - color: var(--color-text-secondary); - font-weight: 500; - transition: color 0.2s; -} - -.header-nav a:hover { - color: var(--color-text-primary); -} - -.profile-btn { - padding: 8px 16px; - border: none; - border-radius: var(--border-radius-md); - background: var(--color-text-primary); - color: var(--color-background-primary); - cursor: pointer; - font-weight: 600; -} - -/* Footer */ -.site-footer { - width: 100%; - max-width: 1200px; - margin: 16px auto 0 auto; - padding: 16px 24px; - background: var(--color-background-primary); - border: 1px solid var(--color-border-tertiary); - border-radius: var(--border-radius-lg); - box-shadow: var(--shadow-md); - - display: flex; - align-items: center; - justify-content: space-between; - color: var(--color-text-secondary); - font-size: 14px; -} - -.footer-links { - display: flex; - gap: 16px; -} - -.footer-links a { - text-decoration: none; - color: var(--color-text-secondary); -} - -.footer-links a:hover { - color: var(--color-text-primary); -} - -/* Settings Toggle Switch */ -.toggle-switch { - position: relative; - display: inline-block; - width: 44px; - height: 24px; -} - -.toggle-switch input { - opacity: 0; - width: 0; - height: 0; -} - -.toggle-slider { - position: absolute; - cursor: pointer; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: var(--color-border-primary); - transition: .3s; - border-radius: 24px; -} - -.toggle-slider:before { - position: absolute; - content: ""; - height: 18px; - width: 18px; - left: 3px; - bottom: 3px; - background-color: var(--color-background-primary); - transition: .3s; - border-radius: 50%; -} - -.toggle-switch input:checked+.toggle-slider { - background-color: var(--color-text-success); -} - -.toggle-switch input:checked+.toggle-slider:before { - transform: translateX(20px); -} - -/* Compact View utility classes */ -body.compact-view { - padding: 16px 8px; -} - -body.compact-view .app { - height: 600px; -} - -body.compact-view .task-item { - padding: 8px 10px; - margin-bottom: 4px; -} - -body.compact-view .nav-item { - padding: 8px 10px; - font-size: 13px; -} - -body.compact-view .topbar { - padding: 12px 16px; -} - -body.compact-view .cal-section, -body.compact-view .tasks-section { - padding: 12px 16px; -} - -/* css/index.css */ -*, -*::before, -*::after { - box-sizing: border-box; - margin: 0; - padding: 0; -} - -:root { - --color-background-primary: #ffffff; - --color-background-secondary: #f7f7f5; - --color-background-tertiary: #efefec; - --color-text-primary: #1a1a18; - --color-text-secondary: #6b6b66; - --color-text-tertiary: #9c9a92; - --color-border-tertiary: rgba(0, 0, 0, 0.08); - /* softer */ - --color-border-secondary: rgba(0, 0, 0, 0.15); - /* softer */ - --color-border-primary: rgba(0, 0, 0, 0.30); - - --color-danger-rgb: 163, 45, 45; - --color-info-rgb: 24, 95, 165; - --color-success-rgb: 22, 101, 52; - - --color-text-danger: #a32d2d; - --color-background-danger: #fcebeb; - --color-border-danger: rgba(var(--color-danger-rgb), 0.35); - - --color-text-info: #185fa5; - --color-background-info: #e6f1fb; - --color-border-info: rgba(var(--color-info-rgb), 0.35); - - --color-text-success: #166534; - --color-background-success: #eaf3de; - --color-border-success: rgba(var(--color-success-rgb), 0.35); - - --color-text-warning: #854f0b; - --color-background-warning: #faeeda; - - --color-text-purple: #3c3489; - --color-background-purple: #eeedfe; - - --border-radius-sm: 6px; - --border-radius-md: 10px; - --border-radius-lg: 16px; - --font-sans: 'Inter', system-ui, -apple-system, sans-serif; - - --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.04); - --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.06); - --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.08); -} - -@media (prefers-color-scheme: dark) { - :root { - --color-background-primary: #181816; - --color-background-secondary: #20201e; - --color-background-tertiary: #272725; - --color-text-primary: #efede5; - --color-text-secondary: #a3a198; - --color-text-tertiary: #73726c; - --color-border-tertiary: rgba(255, 255, 255, 0.06); - --color-border-secondary: rgba(255, 255, 255, 0.12); - --color-border-primary: rgba(255, 255, 255, 0.22); - --color-text-danger: #fc9c9c; - --color-background-danger: rgba(252, 156, 156, 0.15); - --color-border-danger: rgba(252, 156, 156, 0.3); - - --color-text-info: #9ecdfc; - --color-background-info: rgba(158, 205, 252, 0.15); - --color-border-info: rgba(158, 205, 252, 0.3); - - --color-text-success: #a0d45a; - --color-background-success: rgba(160, 212, 90, 0.15); - --color-border-success: rgba(160, 212, 90, 0.3); - - --color-text-warning: #fab35e; - --color-background-warning: rgba(250, 179, 94, 0.15); - - --color-text-purple: #b9b5f5; - --color-background-purple: rgba(185, 181, 245, 0.15); - } -} - -body { - font-family: var(--font-sans); - background: var(--color-background-tertiary); - color: var(--color-text-primary); - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 32px 16px; - overflow-x: hidden; -} - -/* Animations */ -@keyframes fadeIn { - from { - opacity: 0; - transform: translateY(5px); - } - - to { - opacity: 1; - transform: translateY(0); - } -} - -@keyframes popIn { - 0% { - transform: scale(0.95); - opacity: 0; - } - - 100% { - transform: scale(1); - opacity: 1; - } -} - -.wrapper { - width: 100%; - max-width: 1200px; - animation: fadeIn 0.6s cubic-bezier(0.16, 1, 0.3, 1); -} - -.label { - font-size: 12px; - font-weight: 600; - color: var(--color-text-tertiary); - letter-spacing: .08em; - margin-bottom: 12px; - text-transform: uppercase; -} - -.app { - display: grid; - grid-template-columns: 240px 1fr var(--panel-width, 340px); - height: 720px; - border: 1px solid var(--color-border-tertiary); - border-radius: var(--border-radius-lg); - overflow: hidden; - background: var(--color-background-primary); - box-shadow: var(--shadow-lg); - backdrop-filter: blur(20px); -} - -/* Sidebar */ -.sidebar { - background: var(--color-background-secondary); - border-right: 1px solid var(--color-border-tertiary); - padding: 20px 16px; - display: flex; - flex-direction: column; - gap: 4px; -} - -.sidebar-header { - font-size: 11px; - font-weight: 700; - color: var(--color-text-tertiary); - padding: 8px 12px; - margin-bottom: 2px; - letter-spacing: .06em; - text-transform: uppercase; -} - -.nav-item { - display: flex; - align-items: center; - gap: 12px; - padding: 10px 12px; - border-radius: var(--border-radius-md); - cursor: pointer; - font-size: 14px; - font-weight: 500; - color: var(--color-text-secondary); - transition: all 0.2s ease; - position: relative; -} - -.nav-item:hover { - background: var(--color-background-primary); - color: var(--color-text-primary); - transform: translateX(2px); -} - -.nav-item.active { - background: var(--color-background-primary); - color: var(--color-text-primary); - box-shadow: var(--shadow-sm); -} - -.nav-item.active::before { - content: ''; - position: absolute; - left: 0; - top: 15%; - height: 70%; - width: 3px; - background: var(--color-text-primary); - border-radius: 4px; -} - -.nav-dot { - width: 10px; - height: 10px; - border-radius: 50%; - flex-shrink: 0; - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1); -} - -.badge { - margin-left: auto; - font-size: 12px; - font-weight: 600; - background: var(--color-background-tertiary); - color: var(--color-text-secondary); - padding: 2px 8px; - border-radius: 12px; - transition: all 0.2s; -} - -.nav-item:hover .badge { - background: var(--color-background-primary); - border: 1px solid var(--color-border-tertiary); -} - -.sidebar-divider { - height: 1px; - background: var(--color-border-tertiary); - margin: 12px 0; -} - -.add-subject { - font-size: 13px; - font-weight: 500; - color: var(--color-text-tertiary); - padding: 8px 12px; - cursor: pointer; - transition: color 0.2s; - display: flex; - align-items: center; - gap: 8px; -} - -.add-subject:hover { - color: var(--color-text-primary); -} - -/* Main */ -.main { - display: flex; - flex-direction: column; - overflow: hidden; - position: relative; -} - -.topbar { - display: flex; - align-items: center; - gap: 12px; - padding: 16px 24px; - border-bottom: 1px solid var(--color-border-tertiary); - flex-shrink: 0; - background: rgba(var(--color-background-primary), 0.8); - backdrop-filter: blur(10px); - z-index: 10; -} - -.topbar-title { - font-size: 18px; - font-weight: 600; - color: var(--color-text-primary); - flex: 1; -} - -.btn { - font-family: inherit; - font-size: 13px; - font-weight: 600; - padding: 8px 16px; - border: 1px solid var(--color-border-secondary); - border-radius: var(--border-radius-sm); - background: var(--color-background-primary); - color: var(--color-text-primary); - cursor: pointer; - transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); - box-shadow: var(--shadow-sm); - display: inline-flex; - align-items: center; - justify-content: center; - gap: 6px; -} - -.btn:hover { - background: var(--color-background-secondary); - transform: translateY(-1px); - box-shadow: var(--shadow-md); -} - -.btn:active { - transform: translateY(0); - box-shadow: 0 0 0; -} - -.btn-primary { - background: var(--color-text-primary); - color: var(--color-background-primary); - border-color: transparent; -} - -.btn-primary:hover { - background: var(--color-text-secondary); -} - -/* Calendar */ -.cal-section { - padding: 16px 24px; - border-bottom: 1px solid var(--color-border-tertiary); - flex-shrink: 0; -} - -.cal-header { - display: flex; - align-items: center; - margin-bottom: 16px; -} - -.cal-title { - font-size: 15px; - font-weight: 600; - flex: 1; - color: var(--color-text-primary); -} - -.cal-nav { - font-size: 18px; - color: var(--color-text-secondary); - cursor: pointer; - padding: 4px 8px; - border-radius: 4px; - transition: background 0.2s; -} - -.cal-nav:hover { - background: var(--color-background-secondary); - color: var(--color-text-primary); -} - -.cal-grid { - display: grid; - grid-template-columns: repeat(7, 1fr); - gap: 4px; - text-align: center; -} - -.cal-day-label { - font-size: 11px; - color: var(--color-text-tertiary); - padding-bottom: 8px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.05em; -} - -.cal-day { - font-size: 13px; - font-weight: 500; - height: 32px; - display: flex; - align-items: center; - justify-content: center; - border-radius: var(--border-radius-md); - cursor: pointer; - color: var(--color-text-secondary); - position: relative; - transition: all 0.2s; -} - -.cal-day:hover { - background: var(--color-background-secondary); - color: var(--color-text-primary); - transform: scale(1.1); - z-index: 1; -} - -.cal-day.today { - background: var(--color-text-primary); - color: var(--color-background-primary); - box-shadow: var(--shadow-sm); -} - -.cal-day-indicators { - position: absolute; - bottom: 3px; - left: 0; - right: 0; - display: flex; - justify-content: center; - gap: 3px; -} - -.cal-day-indicator { - width: 5px; - height: 5px; - border-radius: 50%; -} - -.cal-day.muted { - color: var(--color-border-secondary); -} - -.cal-legend { - display: flex; - gap: 16px; - margin-top: 16px; - font-size: 11px; - font-weight: 500; - color: var(--color-text-tertiary); - justify-content: flex-end; -} - -.cal-legend span { - display: flex; - align-items: center; - gap: 6px; -} - -.legend-dot { - width: 8px; - height: 8px; - border-radius: 50%; - display: inline-block; -} - -/* Tasks */ -.tasks-section { - flex: 1; - overflow-y: auto; - padding: 0 24px 24px; - scroll-behavior: smooth; -} - -.tasks-section::-webkit-scrollbar { - width: 6px; -} - -.tasks-section::-webkit-scrollbar-thumb { - background: var(--color-border-secondary); - border-radius: 10px; -} - -.tasks-actions-bar { - margin-top: 18px; - display: flex; - gap: 10px; - flex-wrap: wrap; -} - -.task-action-btn { - border: 1px solid var(--color-border-success); - background: var(--color-background-success); - color: var(--color-text-success); - border-radius: var(--border-radius-sm); - padding: 7px 12px; - font-size: 12px; - font-weight: 700; - cursor: pointer; - transition: all 0.2s ease; -} - -.task-action-btn:hover { - filter: brightness(0.98); - transform: translateY(-1px); -} - -.task-action-btn:disabled { - opacity: 0.55; - cursor: not-allowed; - transform: none; - filter: none; -} - -.task-action-btn-secondary { - border-color: var(--color-border-info); - background: var(--color-background-info); - color: var(--color-text-info); -} - -.tasks-empty-state { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - text-align: center; - padding: 60px 24px; - margin-top: 24px; - background: var(--color-background-secondary); - border: 1px dashed var(--color-border-secondary); - border-radius: var(--border-radius-lg); - position: relative; - overflow: hidden; - animation: emptyStateFadeIn 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards; -} - -@keyframes emptyStateFadeIn { - from { opacity: 0; transform: translateY(10px); } - to { opacity: 1; transform: translateY(0); } -} - -.empty-state-icon { - font-size: 48px; - margin-bottom: 16px; - position: relative; - z-index: 1; - filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.05)); - animation: float 3s ease-in-out infinite; -} - -/* Soft gradient glow behind the icon */ -.empty-state-icon::before { - content: ''; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 80px; - height: 80px; - background: radial-gradient(circle, rgba(79, 70, 229, 0.15) 0%, transparent 70%); - z-index: -1; - border-radius: 50%; -} - -.empty-state-title { - font-size: 18px; - font-weight: 600; - color: var(--color-text-primary); - margin-bottom: 8px; -} - -.empty-state-text { - font-size: 14px; - color: var(--color-text-secondary); - max-width: 300px; - line-height: 1.5; - margin-bottom: 24px; -} - -.empty-state-cta { - display: inline-flex; - align-items: center; - gap: 8px; - padding: 10px 20px; - background: var(--color-text-primary); - color: var(--color-background-primary); - border-radius: 8px; - font-size: 14px; - font-weight: 600; - text-decoration: none; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - border: none; - cursor: pointer; - box-shadow: var(--shadow-sm); - position: relative; - overflow: hidden; -} - -.empty-state-cta:hover { - transform: translateY(-3px) scale(1.02); - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12); - filter: brightness(1.2); -} - -.empty-state-cta:active { - transform: translateY(-1px) scale(0.98); -} - -/* Subtle shine effect on hover */ -.empty-state-cta::after { - content: ''; - position: absolute; - top: 0; - left: -100%; - width: 50%; - height: 100%; - background: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.2), transparent); - transition: left 0.6s ease; -} - -.empty-state-cta:hover::after { - left: 150%; -} - -@keyframes float { - 0%, 100% { transform: translateY(0); } - 50% { transform: translateY(-10px); } -} - -.tasks-group { - margin-top: 24px; - animation: fadeIn 0.4s ease forwards; -} - -.tasks-group-header { - display: flex; - align-items: center; - gap: 8px; - margin-bottom: 12px; -} - -.tasks-group-header span { - font-size: 12px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.05em; -} - -.task-item { - display: flex; - align-items: flex-start; - gap: 14px; - padding: 12px 14px; - border-radius: var(--border-radius-md); - cursor: pointer; - transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); - border: 1px solid transparent; - background: var(--color-background-primary); - margin-bottom: 6px; - border: 1px solid var(--color-border-tertiary); -} - -.task-item:hover { - background: var(--color-background-secondary); - transform: translateX(4px); - border-color: var(--color-border-secondary); - box-shadow: var(--shadow-sm); -} - -.task-item.urgent { - border-color: var(--color-border-danger); - background: linear-gradient(to right, var(--color-background-danger) 0%, var(--color-background-primary) 100%); -} - -.task-check { - width: 18px; - height: 18px; - border-radius: 5px; - border: 2px solid var(--color-border-secondary); - flex-shrink: 0; - margin-top: 2px; - transition: all 0.2s; - position: relative; - cursor: pointer; -} - -.task-check:hover { - border-color: var(--color-text-primary); -} - -.task-check.done { - background: var(--color-text-success); - border-color: var(--color-text-success); -} - -.task-check.done::after { - content: ''; - position: absolute; - left: 4px; - top: 1px; - width: 4px; - height: 8px; - border: solid white; - border-width: 0 2px 2px 0; - transform: rotate(45deg); -} - -.task-info { - flex: 1; - min-width: 0; -} - -.task-name { - font-size: 14px; - font-weight: 500; - color: var(--color-text-primary); - line-height: 1.4; - transition: color 0.2s; - margin-bottom: 6px; -} - -.task-item.done .task-name { - text-decoration: line-through; - color: var(--color-text-tertiary); -} - -.task-meta { - font-size: 12px; - color: var(--color-text-tertiary); - margin-top: 6px; - display: flex; - gap: 8px; - flex-wrap: wrap; - align-items: center; - font-weight: 500; -} - -.task-pill { - font-size: 11px; - padding: 2px 8px; - border-radius: 12px; - font-weight: 600; - display: inline-flex; - align-items: center; - gap: 4px; - border: 1px solid transparent; -} - -.pill-red { - background: var(--color-background-danger); - color: var(--color-text-danger); - border-color: var(--color-border-danger); -} - -.pill-blue { - background: var(--color-background-info); - color: var(--color-text-info); - border-color: var(--color-border-info); -} - -.pill-green { - background: var(--color-background-success); - color: var(--color-text-success); - border-color: var(--color-border-success); -} - -.pill-amber { - background: var(--color-background-warning); - color: var(--color-text-warning); - border-color: rgba(133, 79, 11, 0.2); -} - -.pill-purple { - background: var(--color-background-purple); - color: var(--color-text-purple); - border-color: rgba(60, 52, 137, 0.2); -} - -.conflict-card { - font-size: 13px; - font-weight: 500; - color: var(--color-text-warning); - background: var(--color-background-warning); - border: 1px solid rgba(133, 79, 11, 0.3); - border-radius: var(--border-radius-md); - padding: 12px 16px; - line-height: 1.5; - display: flex; - gap: 12px; - align-items: flex-start; - box-shadow: var(--shadow-sm); -} - -.conflict-icon { - font-size: 18px; - line-height: 1; -} -.task-item:hover { background: var(--color-background-secondary); transform: translateX(4px); border-color: var(--color-border-secondary); box-shadow: var(--shadow-sm); } -.task-item.urgent, .task-item.high-priority { - border-color: var(--color-border-danger); - background: linear-gradient(135deg, rgba(var(--color-danger-rgb), 0.08) 0%, var(--color-background-primary) 100%); -} -.task-item.overdue { - border-color: var(--color-border-danger); - background: linear-gradient(135deg, rgba(var(--color-danger-rgb), 0.12) 0%, var(--color-background-primary) 100%); -} -.task-item.done { - background: linear-gradient(135deg, rgba(var(--color-success-rgb), 0.08) 0%, var(--color-background-primary) 100%); - border-color: var(--color-border-success); -} -.task-check { width: 18px; height: 18px; border-radius: 5px; border: 2px solid var(--color-border-secondary); flex-shrink: 0; margin-top: 2px; transition: all 0.2s; position: relative; cursor: pointer; } -.task-check:hover { border-color: var(--color-text-primary); } -.task-check.done { background: var(--color-text-success); border-color: var(--color-text-success); } -.task-check.done::after { content: ''; position: absolute; left: 4px; top: 1px; width: 4px; height: 8px; border: solid white; border-width: 0 2px 2px 0; transform: rotate(45deg); } -.task-info { flex: 1; min-width: 0; } -.task-name { font-size: 14px; font-weight: 500; color: var(--color-text-primary); line-height: 1.4; transition: color 0.2s; margin-bottom: 6px; } -.task-item.done .task-name { text-decoration: line-through; color: var(--color-text-tertiary); } -.task-meta { font-size: 12px; color: var(--color-text-tertiary); margin-top: 6px; display: flex; gap: 8px; flex-wrap: wrap; align-items: center; font-weight: 500; } -.task-pill { font-size: 11px; padding: 2px 8px; border-radius: 12px; font-weight: 600; display: inline-flex; align-items: center; gap: 4px; border: 1px solid transparent; } -.pill-red { background: var(--color-background-danger); color: var(--color-text-danger); border-color: var(--color-border-danger); } -.pill-blue { background: var(--color-background-info); color: var(--color-text-info); border-color: var(--color-border-info); } -.pill-green{ background: var(--color-background-success); color: var(--color-text-success); border-color: var(--color-border-success); } -.pill-amber{ background: var(--color-background-warning); color: var(--color-text-warning); border-color: rgba(133, 79, 11, 0.2); } -.pill-purple{ background: var(--color-background-purple); color: var(--color-text-purple); border-color: rgba(60, 52, 137, 0.2); } - -.conflict-card { font-size: 13px; font-weight: 500; color: var(--color-text-warning); background: var(--color-background-warning); border: 1px solid rgba(133, 79, 11, 0.3); border-radius: var(--border-radius-md); padding: 12px 16px; line-height: 1.5; display: flex; gap: 12px; align-items: flex-start; box-shadow: var(--shadow-sm); } -.conflict-icon { font-size: 18px; line-height: 1; } - -.task-actions { - display: flex; - gap: 8px; - opacity: 0; - transition: opacity 0.2s; -} - -.task-item:hover .task-actions { - opacity: 1; -} - -.task-btn { - padding: 4px 8px; - border-radius: 4px; - font-size: 11px; - font-weight: 600; - cursor: pointer; - border: 1px solid var(--color-border-secondary); - background: var(--color-background-primary); - color: var(--color-text-secondary); - transition: all 0.2s; -} - -.task-btn:hover { - background: var(--color-background-secondary); - color: var(--color-text-primary); - border-color: var(--color-border-primary); -} - -.task-btn-danger:hover { - background: var(--color-background-danger); - color: var(--color-text-danger); - border-color: var(--color-text-danger); -} - -.task-btn-info:hover { - background: var(--color-background-info); - color: var(--color-text-info); - border-color: var(--color-text-info); -} - -/* Right Panel */ -.panel { - border-left: 1px solid var(--color-border-tertiary); - display: flex; - flex-direction: column; - background: var(--color-background-secondary); - overflow: hidden; -} - -.panel.panel-collapsed { - overflow: hidden; - width: 48px; - min-width: 48px; -} -.summary-box { - margin-top: 16px; - padding: 14px; - background: var(--color-background-secondary); - color: var(--color-text-primary); - border-radius: 12px; - font-size: 14px; - line-height: 1.6; - border: 1px solid var(--color-border-tertiary); -} - -.panel.panel-collapsed .panel-title, -.panel.panel-collapsed .panel-subtitle, -.panel.panel-collapsed .paste-zone, -.panel.panel-collapsed .paste-actions, -.panel.panel-collapsed .extract-preview, -.panel.panel-collapsed .add-btn { - display: none; -} - -.panel-header { - padding: 20px 24px 16px; - border-bottom: 1px solid var(--color-border-tertiary); - background: var(--color-background-primary); - flex-shrink: 0; - display: flex; - align-items: flex-start; - gap: 10px; -} - -.panel.panel-collapsed .panel-header { - padding: 12px; - justify-content: center; - border-bottom: none; - overflow: hidden; -} - -.panel-toggle-btn { - flex-shrink: 0; - background: none; - border: 1px solid var(--color-border-secondary); - border-radius: var(--border-radius-sm); - width: 28px; - height: 28px; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - color: var(--color-text-secondary); - transition: all 0.2s; - margin-top: 2px; -} - -.panel-toggle-btn:hover { - background: var(--color-background-secondary); - color: var(--color-text-primary); -} - -.panel-toggle-icon { - transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); -} - -.panel-title { - font-size: 16px; - font-weight: 600; - color: var(--color-text-primary); - display: flex; - align-items: center; - gap: 8px; -} - -.panel-title svg { - opacity: 0.8; -} - -.panel-subtitle { - font-size: 12px; - font-weight: 500; - color: var(--color-text-tertiary); - margin-top: 4px; -} - -.paste-zone { - margin: 20px 20px 12px; - border: 2px dashed var(--color-border-secondary); - border-radius: var(--border-radius-lg); - padding: 24px 20px; - text-align: center; - cursor: text; - transition: all 0.2s; - background: var(--color-background-primary); - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - position: relative; - min-height: 120px; - overflow: hidden; -} - -.paste-zone:hover { - border-color: var(--color-text-info); - background: var(--color-background-info); -} - -.paste-zone:focus-within { - border-color: var(--color-text-primary); - border-style: solid; - box-shadow: inset 0 0 0 1px var(--color-text-primary); - outline: none; -} - -.paste-icon { - font-size: 24px; - margin-bottom: 8px; - color: var(--color-text-secondary); - transition: color 0.2s; -} - -.paste-zone:hover .paste-icon { - color: var(--color-text-info); -} - -.paste-input { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - width: 100%; - height: 100%; - opacity: 0; - resize: none; - border: none; - padding: 20px; - font-family: inherit; - font-size: 13px; - z-index: 2; -} - -.paste-input:focus, -.paste-input:not(:placeholder-shown) { - opacity: 1; - z-index: 10; - background: var(--color-background-primary); - color: var(--color-text-primary); - outline: none; -} - -.paste-label { - font-size: 14px; - font-weight: 600; - color: var(--color-text-primary); - margin-bottom: 4px; - pointer-events: none; -} - -.paste-hint { - font-size: 12px; - color: var(--color-text-tertiary); - line-height: 1.5; - pointer-events: none; -} - -.paste-actions { - padding: 0 20px 16px; -} -/* Main */ -.main { display: flex; flex-direction: column; overflow: hidden; position: relative; } -.topbar { position: relative; display: flex; align-items: center; justify-content: space-between; padding: 16px 24px; border-bottom: 1px solid var(--color-border-tertiary); flex-shrink: 0; background: rgba(var(--color-background-primary), 0.8); backdrop-filter: blur(10px); z-index: 10; } -.topbar-title { font-size: 18px; font-weight: 700; color: var(--color-text-primary); } -.btn { font-family: inherit; font-size: 13px; font-weight: 600; padding: 8px 16px; border: 1px solid var(--color-border-secondary); border-radius: var(--border-radius-sm); background: var(--color-background-primary); color: var(--color-text-primary); cursor: pointer; transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: var(--shadow-sm); display: inline-flex; align-items: center; justify-content: center; gap: 6px; } -.btn:hover { background: var(--color-background-secondary); transform: translateY(-1px); box-shadow: var(--shadow-md); } -.btn:active { transform: translateY(0); box-shadow: 0 0 0; } -.btn-primary { background: var(--color-text-primary); color: var(--color-background-primary); border-color: transparent; } -.btn-primary:hover { background: var(--color-text-secondary); } - -/* Calendar */ -.cal-section { padding: 16px 24px; border-bottom: 1px solid var(--color-border-tertiary); flex-shrink: 0; } -.cal-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 16px; } -.cal-header-left { display: flex; flex-direction: column; flex: 1; align-items: flex-start; gap: 4px; } -.cal-header-right { display: flex; align-items: center; } -.cal-title { font-size: 15px; font-weight: 600; color: var(--color-text-primary); } -.cal-nav { font-size: 18px; color: var(--color-text-secondary); cursor: pointer; padding: 4px 8px; border-radius: 4px; transition: background 0.2s; } -.cal-nav:hover { background: var(--color-background-secondary); color: var(--color-text-primary); } -.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; text-align: center; } -.cal-day-label { font-size: 11px; color: var(--color-text-tertiary); padding-bottom: 8px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; } -.cal-day { font-size: 13px; font-weight: 500; height: 32px; display: flex; align-items: center; justify-content: center; border-radius: var(--border-radius-md); cursor: pointer; color: var(--color-text-secondary); position: relative; transition: all 0.2s; } -.cal-day:hover { background: var(--color-background-secondary); color: var(--color-text-primary); transform: scale(1.1); z-index: 1; } -.cal-day.today { background: var(--color-text-primary); color: var(--color-background-primary); box-shadow: var(--shadow-sm); } -.cal-day-indicators { position: absolute; bottom: 3px; left: 0; right: 0; display: flex; justify-content: center; gap: 3px; } -.cal-day-indicator { width: 5px; height: 5px; border-radius: 50%; } -.cal-day.muted { color: var(--color-border-secondary); } -.cal-legend { display: flex; gap: 16px; margin-top: 16px; font-size: 11px; font-weight: 500; color: var(--color-text-tertiary); justify-content: flex-end; } -.cal-legend span { display: flex; align-items: center; gap: 6px; } -.legend-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; } - -/* Quote Widget */ -.quote-widget { - display: inline-flex; - align-items: center; - gap: 6px; - padding: 6px 12px; - background: var(--color-background-secondary); - border: 1px solid var(--color-border-tertiary); - border-radius: 100px; - transition: all 0.2s ease; -} -.quote-widget:hover { - background: var(--color-background-tertiary); - transform: translateY(-1px); -} -.quote-icon { - color: var(--color-text-tertiary); -} -.quote-widget p { - margin: 0; - font-size: 11px; - color: var(--color-text-secondary); - font-weight: 600; - line-height: 1; - letter-spacing: 0.02em; -} - -/* Tasks */ -.tasks-section { flex: 1; overflow-y: auto; padding: 0 24px 24px; scroll-behavior: smooth; } -.tasks-section::-webkit-scrollbar { width: 6px; } -.tasks-section::-webkit-scrollbar-thumb { background: var(--color-border-secondary); border-radius: 10px; } -.tasks-actions-bar { - margin-top: 18px; - display: flex; - gap: 12px; -} - -.extract-preview { - overflow-y: auto; - padding: 0 20px 12px; - scroll-behavior: smooth; - max-height: 280px; -} - -.extract-preview::-webkit-scrollbar { - width: 6px; -} - -.extract-preview::-webkit-scrollbar-thumb { - background: var(--color-border-secondary); - border-radius: 10px; -} - -.extract-title { - font-size: 11px; - font-weight: 700; - color: var(--color-text-tertiary); - margin-bottom: 12px; - letter-spacing: .06em; - text-transform: uppercase; - display: flex; - align-items: center; - justify-content: space-between; -} - -.extract-card { - background: var(--color-background-primary); - border: 1px solid var(--color-border-tertiary); - border-radius: var(--border-radius-md); - padding: 14px 16px; - margin-bottom: 12px; - box-shadow: var(--shadow-sm); - animation: popIn 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; - transform-origin: center; - position: relative; - overflow: hidden; -} - -.tasks-empty-state { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - text-align: center; - padding: 60px 24px; - margin-top: 24px; - background: var(--color-background-secondary); - border: 1px dashed var(--color-border-secondary); - border-radius: var(--border-radius-lg); - position: relative; - overflow: hidden; - animation: emptyStateFadeIn 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards; -} - -@keyframes emptyStateFadeIn { - from { opacity: 0; transform: translateY(10px); } - to { opacity: 1; transform: translateY(0); } -} - -.empty-state-icon { - font-size: 48px; - margin-bottom: 16px; - position: relative; - z-index: 1; - filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.05)); - animation: float 3s ease-in-out infinite; -} - -/* Soft gradient glow behind the icon */ -.empty-state-icon::before { - content: ''; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 80px; - height: 80px; - background: radial-gradient(circle, rgba(79, 70, 229, 0.15) 0%, transparent 70%); - z-index: -1; - border-radius: 50%; -} - -.empty-state-title { - font-size: 18px; - font-weight: 600; - color: var(--color-text-primary); - margin-bottom: 8px; -} - -.empty-state-text { - font-size: 14px; - color: var(--color-text-secondary); - max-width: 300px; - line-height: 1.5; - margin-bottom: 24px; -} - -.empty-state-cta { - display: inline-flex; - align-items: center; - gap: 8px; - padding: 10px 20px; - background: var(--color-text-primary); - color: var(--color-background-primary); - border-radius: 8px; - font-size: 14px; - font-weight: 600; - text-decoration: none; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - border: none; - cursor: pointer; - box-shadow: var(--shadow-sm); - position: relative; - overflow: hidden; -} - -.empty-state-cta:hover { - transform: translateY(-3px) scale(1.02); - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12); - filter: brightness(1.2); -} - -.empty-state-cta:active { - transform: translateY(-1px) scale(0.98); -} - -/* Subtle shine effect on hover */ -.empty-state-cta::after { - content: ''; - position: absolute; - top: 0; - left: -100%; - width: 50%; - height: 100%; - background: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.2), transparent); - transition: left 0.6s ease; -} - -.empty-state-cta:hover::after { - left: 150%; -} - -@keyframes float { - 0%, 100% { transform: translateY(0); } - 50% { transform: translateY(-10px); } -} - -.extract-subject { - font-size: 11px; - font-weight: 700; - margin-bottom: 6px; - letter-spacing: .04em; - text-transform: uppercase; -} -.task-item:hover { background: var(--color-background-secondary); transform: translateX(4px); border-color: var(--color-border-secondary); box-shadow: var(--shadow-sm); } -.task-item.urgent, .task-item.high-priority { - border-color: var(--color-border-danger); - background: linear-gradient(135deg, rgba(var(--color-danger-rgb), 0.08) 0%, var(--color-background-primary) 100%); -} -.task-item.overdue { - border-color: var(--color-border-danger); - background: linear-gradient(135deg, rgba(var(--color-danger-rgb), 0.12) 0%, var(--color-background-primary) 100%); -} -.task-item.done { - background: linear-gradient(135deg, rgba(var(--color-success-rgb), 0.08) 0%, var(--color-background-primary) 100%); - border-color: var(--color-border-success); -} -.task-check { width: 18px; height: 18px; border-radius: 5px; border: 2px solid var(--color-border-secondary); flex-shrink: 0; margin-top: 2px; transition: all 0.2s; position: relative; cursor: pointer; } -.task-check:hover { border-color: var(--color-text-primary); } -.task-check.done { background: var(--color-text-success); border-color: var(--color-text-success); } -.task-check.done::after { content: ''; position: absolute; left: 4px; top: 1px; width: 4px; height: 8px; border: solid white; border-width: 0 2px 2px 0; transform: rotate(45deg); } -.task-info { flex: 1; min-width: 0; } -.task-name { font-size: 14px; font-weight: 500; color: var(--color-text-primary); line-height: 1.4; transition: color 0.2s; margin-bottom: 6px; } -.task-item.done .task-name { text-decoration: line-through; color: var(--color-text-tertiary); } -.task-meta { font-size: 12px; color: var(--color-text-tertiary); margin-top: 6px; display: flex; gap: 8px; flex-wrap: wrap; align-items: center; font-weight: 500; } -.task-pill { font-size: 11px; padding: 2px 8px; border-radius: 12px; font-weight: 600; display: inline-flex; align-items: center; gap: 4px; border: 1px solid transparent; } -.pill-red { background: var(--color-background-danger); color: var(--color-text-danger); border-color: var(--color-border-danger); } -.pill-blue { background: var(--color-background-info); color: var(--color-text-info); border-color: var(--color-border-info); } -.pill-green{ background: var(--color-background-success); color: var(--color-text-success); border-color: var(--color-border-success); } -.pill-amber{ background: var(--color-background-warning); color: var(--color-text-warning); border-color: rgba(133, 79, 11, 0.2); } -.pill-purple{ background: var(--color-background-purple); color: var(--color-text-purple); border-color: rgba(60, 52, 137, 0.2); } - -.conflict-card { font-size: 13px; font-weight: 500; color: var(--color-text-warning); background: var(--color-background-warning); border: 1px solid rgba(133, 79, 11, 0.3); border-radius: var(--border-radius-md); padding: 12px 16px; line-height: 1.5; display: flex; gap: 12px; align-items: flex-start; box-shadow: var(--shadow-sm); } -.conflict-icon { font-size: 18px; line-height: 1; } - -.extract-task-name { - font-size: 14px; - font-weight: 600; - color: var(--color-text-primary); - margin-bottom: 8px; - line-height: 1.4; -} - -.extract-row { - display: flex; - align-items: center; - gap: 8px; - font-size: 12px; - font-weight: 500; - color: var(--color-text-secondary); - margin-top: 4px; -} - -.extract-icon { - font-size: 14px; -} - -.conf-bar { - height: 4px; - border-radius: 2px; - margin-top: 12px; - background: var(--color-border-tertiary); - overflow: hidden; -} - -.conf-fill { - height: 100%; - border-radius: 2px; - transition: width 1s cubic-bezier(0.16, 1, 0.3, 1); -} - -.conf-label { - font-size: 11px; - font-weight: 600; - color: var(--color-text-tertiary); - margin-top: 6px; - display: flex; - justify-content: space-between; -} - -.conf-edit { - color: var(--color-text-info); - cursor: pointer; - transition: color 0.2s; -} - -.conf-edit:hover { - color: var(--color-text-primary); -} - -.add-btn { - margin: 0 20px 20px; - padding: 12px; - border: none; - border-radius: var(--border-radius-md); - background: var(--color-text-primary); - color: var(--color-background-primary); - font-size: 14px; - font-weight: 600; - cursor: pointer; - text-align: center; - flex-shrink: 0; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); - transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); -} - -.add-btn:hover:not(:disabled) { - background: var(--color-text-secondary); - transform: translateY(-2px); - box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2); -} - -.add-btn:active:not(:disabled) { - transform: translateY(0); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); -} - -.add-btn:disabled { - background: var(--color-border-secondary); - cursor: not-allowed; - transform: none; - box-shadow: none; - color: var(--color-text-tertiary); -} - -/* Loader */ -.loader-spinner { - display: inline-block; - width: 16px; - height: 16px; - border: 2px solid rgba(0, 0, 0, 0.1); - border-radius: 50%; - border-top-color: var(--color-text-primary); - animation: spin 0.8s linear infinite; -} - -@media (prefers-color-scheme: dark) { - .loader-spinner { - border-color: rgba(255, 255, 255, 0.1); - border-top-color: #fff; - } -} - -@keyframes spin { - to { - transform: rotate(360deg); - } -} - -/* Utility classes */ -.hidden { - display: none !important; -} - -/* Timer duration input */ -.timer-duration-row { - display: flex; - align-items: center; - gap: 10px; -} - -.timer-duration-label { - font-size: 12px; - font-weight: 600; - color: var(--color-text-tertiary); - text-transform: uppercase; - letter-spacing: 0.05em; -} - -.timer-duration-input { - width: 64px; - padding: 6px 10px; - border: 1px solid var(--color-border-secondary); - border-radius: var(--border-radius-sm); - background: var(--color-background-primary); - color: var(--color-text-primary); - font-size: 14px; - font-weight: 600; - font-family: inherit; - text-align: center; - transition: border-color 0.2s; -} - -.timer-duration-input:focus { - outline: none; - border-color: var(--color-text-primary); -} - -.timer-duration-input:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -/* Focus Mode */ -.focus-section { - flex: 1; - display: flex; - flex-direction: column; - padding: 24px; - overflow-y: auto; - gap: 32px; -} - -.focus-dashboard { - display: flex; - flex-direction: column; - align-items: center; - gap: 24px; -} - -.timer-container { - position: relative; - width: 240px; - height: 240px; - display: flex; - align-items: center; - justify-content: center; -} - -.timer-svg { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - transform: rotate(-90deg); -} - -.timer-path-elapsed { - fill: none; - stroke: var(--color-border-tertiary); - stroke-width: 4; -} - -.timer-path-remaining { - fill: none; - stroke: var(--color-text-primary); - stroke-width: 6; - stroke-linecap: round; - transition: stroke-dashoffset 1s linear; -} - -.timer-text { - font-size: 48px; - font-weight: 700; - color: var(--color-text-primary); - font-variant-numeric: tabular-nums; - letter-spacing: -0.02em; - z-index: 1; -} - -.timer-controls { - display: flex; - gap: 12px; -} - -.focus-task-container, -.focus-task-selector { - width: 100%; - max-width: 600px; - margin: 0 auto; -} - -.focus-task-header { - font-size: 13px; - font-weight: 600; - color: var(--color-text-tertiary); - text-transform: uppercase; - letter-spacing: 0.05em; - margin-bottom: 12px; -} - -.active-focus-task { - background: var(--color-background-primary); - border: 1px solid var(--color-border-primary); - border-radius: var(--border-radius-md); - padding: 20px; - box-shadow: var(--shadow-md); - min-height: 80px; - display: flex; - align-items: center; - justify-content: center; -} - -.no-task-selected { - color: var(--color-text-secondary); - font-size: 14px; - font-weight: 500; -} - -.focus-task-list { - display: flex; - flex-direction: column; - gap: 8px; -} - -.focus-task-item { - display: flex; - align-items: center; - gap: 12px; - padding: 12px; - background: var(--color-background-primary); - border: 1px solid var(--color-border-tertiary); - border-radius: var(--border-radius-md); - cursor: pointer; - transition: all 0.2s; -} - -.focus-task-item:hover { - background: var(--color-background-secondary); - border-color: var(--color-text-info); - transform: translateY(-1px); -} - -.focus-task-item .task-name { - margin-bottom: 0; - flex: 1; -} - - -/* Header */ -.site-header { - width: 100%; - max-width: 1200px; - margin: 0 auto 16px auto; - padding: 16px 24px; - background: var(--color-background-primary); - border: 1px solid var(--color-border-tertiary); - border-radius: var(--border-radius-lg); - box-shadow: var(--shadow-md); - - display: flex; - align-items: center; - justify-content: space-between; -} - -.header-left { - display: flex; - align-items: center; - gap: 12px; -} - -.logo { - width: 40px; - height: 40px; - border-radius: 2px; -} - -.site-title { - font-size: 20px; - font-weight: 700; - color: var(--color-text-primary); -} - -.header-nav { - display: flex; - gap: 24px; -} - -.header-nav a { - text-decoration: none; - color: var(--color-text-secondary); - font-weight: 500; - transition: color 0.2s; -} - -.header-nav a:hover { - color: var(--color-text-primary); -} - -.profile-btn { - padding: 8px 16px; - border: none; - border-radius: var(--border-radius-md); - background: var(--color-text-primary); - color: var(--color-background-primary); - cursor: pointer; - font-weight: 600; -} - -/* Footer */ -.site-footer { - width: 100%; - max-width: 1200px; - margin: 16px auto 0 auto; - padding: 16px 24px; - background: var(--color-background-primary); - border: 1px solid var(--color-border-tertiary); - border-radius: var(--border-radius-lg); - box-shadow: var(--shadow-md); - - display: flex; - align-items: center; - justify-content: space-between; - color: var(--color-text-secondary); - font-size: 14px; -} - -.footer-links { - display: flex; - gap: 16px; -} - -.footer-links a { - text-decoration: none; - color: var(--color-text-secondary); -} - -.footer-links a:hover { - color: var(--color-text-primary); -} - -/* Global crash boundary UI */ -.crash-screen { - min-height: 100vh; - width: 100%; - display: flex; - align-items: center; - justify-content: center; - padding: 24px; - background: - radial-gradient(circle at 20% 20%, rgba(24, 95, 165, 0.16), transparent 40%), - radial-gradient(circle at 80% 0%, rgba(22, 101, 52, 0.14), transparent 42%), - var(--color-background-tertiary); -} - -.crash-card { - width: min(560px, 100%); - border-radius: var(--border-radius-lg); - border: 1px solid var(--color-border-tertiary); - background: var(--color-background-primary); - box-shadow: var(--shadow-lg); - padding: 28px; -} - -.crash-illustration { - font-size: 30px; - margin-bottom: 12px; -} - -.crash-title { - font-size: 28px; - margin-bottom: 10px; -} - -.crash-copy { - color: var(--color-text-secondary); - line-height: 1.5; - margin-bottom: 8px; -} - -.crash-quote { - color: var(--color-text-info); - font-weight: 600; - margin-bottom: 16px; -} - -.crash-refresh { - border: none; - border-radius: var(--border-radius-md); - padding: 10px 16px; - font-size: 14px; - font-weight: 700; - color: var(--color-background-primary); - background: var(--color-text-primary); - cursor: pointer; -} - -.crash-refresh:hover { - background: var(--color-text-secondary); -} - -.crash-details { - margin-top: 14px; - color: var(--color-text-secondary); -} - -.crash-details pre { - margin-top: 8px; - white-space: pre-wrap; - overflow-wrap: anywhere; - font-size: 12px; - background: var(--color-background-secondary); - border: 1px solid var(--color-border-tertiary); - border-radius: var(--border-radius-sm); - padding: 10px; -} - -/* Task Addition Model */ - - -#new-task-modal { - - position: fixed; - inset: 0; - z-index: 9998; - display: none; - align-items: center; - justify-content: center; - background-color: rgba(0, 0, 0, 0.55) !important; -} - - -#new-task-modal .modal-card { - width: 100%; - max-width: 360px; - background-color: #0f172a; - border-radius: 14px; - padding: 20px 20px 16px; - box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6) !important; - color: #e5e7eb; - box-sizing: border-box; - border: 1px solid rgba(148, 163, 184, 0.35) !important; -} - - -#new-task-modal .modal-card h3 { - margin: 0 0 12px; - font-size: 18px; - font-weight: 600; - letter-spacing: 0.01em; - color: #f9fafb; -} - - -#new-task-modal label { - display: block; - font-size: 11px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.06em; - color: #9ca3af; - /* muted */ - margin-bottom: 4px; -} - - -#new-task-modal input, -#new-task-modal select { - width: 100%; - box-sizing: border-box; - font-size: 13px; - padding: 7px 8px; - margin-bottom: 10px; - border-radius: 6px; - border: 1px solid #4b5563; - background-color: #111827 !important; - color: #e5e7eb; - transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease; - color-scheme: dark; -} - - -#new-task-modal input::placeholder { - color: #6b7280; -} - - -#new-task-modal input:focus, -#new-task-modal select:focus { - outline: none; - border-color: #4f46e5; - box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.35); - background: #020617; -} - - -#new-task-modal .modal-card>div:last-child { - display: flex; - justify-content: flex-end; - gap: 8px; - margin-top: 6px; -} - - -#new-task-modal .btn { - font-size: 12px; - padding: 6px 10px; - border-radius: 999px; -} - -#new-task-modal .btn:not(.btn-primary) { - background: rgba(15, 23, 42, 0.9); - color: #e5e7eb; - border: 1px solid #4b5563; -} - -#new-task-modal .btn:not(.btn-primary):hover { - background: #020617; -} - - -#new-task-modal.showing .modal-card { - animation: new-task-modal-in 0.16s ease-out; -} - -@keyframes new-task-modal-in { - from { - opacity: 0; - transform: translateY(6px) scale(0.97); - } - - to { - opacity: 1; - transform: translateY(0) scale(1); - } -} - - -@media (max-width: 480px) { - #new-task-modal .modal-card { - max-width: 90vw; - padding: 16px 14px 12px; - } -} - - -.smart-workload-card { - margin-bottom: 14px; - padding: 14px; - border-radius: 14px; - background: rgba(255, 184, 77, 0.08); - border: 1px solid rgba(255, 184, 77, 0.25); - backdrop-filter: blur(10px); - display: flex; - justify-content: space-between; - gap: 18px; - align-items: flex-start; - flex-wrap: wrap; -} - -.smart-workload-title { - font-size: 14px; - font-weight: 700; - margin-bottom: 8px; - color: #ffcc66; -} - -.smart-workload-score { - min-width: 90px; - font-size: 12px; - margin-bottom: 10px; - color: #cfcfcf; -} - -.smart-suggestion-list { - margin: 0; - padding-left: 18px; -} - -.smart-suggestion-list li { - margin-bottom: 6px; - color: #e6e6e6; - line-height: 1.5; - font-size: 13px; -} - -.smart-workload-card.high { - border-color: rgba(255, 77, 77, 0.5); - background: rgba(255, 77, 77, 0.08); -} - -.smart-workload-card.medium { - border-color: rgba(255, 184, 77, 0.25); -} - -.smart-highlight { - color: #ffcc66; - font-weight: 600; -} - -/* ========================================================================== - Modern Toast Notifications - ========================================================================== */ - -.toast-container { - position: fixed; - top: 24px; - right: 24px; - z-index: 10000; - display: flex; - flex-direction: column; - gap: 12px; - pointer-events: none; -} - -.toast-notification { - pointer-events: auto; - display: flex; - align-items: center; - gap: 12px; - background: var(--color-background-primary); - color: var(--color-text-primary); - padding: 12px 16px; - border-radius: 12px; - box-shadow: 0 8px 30px rgba(0, 0, 0, 0.2); - border: 1px solid var(--color-border-secondary); - font-family: 'Inter', sans-serif; - font-size: 14px; - font-weight: 500; - animation: toastSlideIn 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; - max-width: 350px; - transform-origin: top right; -} - -.toast-notification.toast-hiding { - animation: toastSlideOut 0.2s ease-in forwards; -} - -.toast-icon { - font-size: 18px; - flex-shrink: 0; -} - -.toast-message { - flex-grow: 1; - line-height: 1.4; -} - -.toast-close { - background: none; - border: none; - color: var(--color-text-tertiary); - font-size: 18px; - cursor: pointer; - padding: 0; - margin-left: 8px; - flex-shrink: 0; - display: flex; - align-items: center; - justify-content: center; - transition: color 0.2s; -} - -.toast-close:hover { - color: var(--color-text-primary); -} - -/* Toast Themes */ -.toast-success { border-left: 4px solid var(--color-text-success); } -.toast-error { border-left: 4px solid var(--color-text-danger); } -.toast-warning { border-left: 4px solid var(--color-text-warning); } -.toast-info { border-left: 4px solid var(--color-text-info); } - -@keyframes toastSlideIn { - from { opacity: 0; transform: translateY(-20px) scale(0.95); } - to { opacity: 1; transform: translateY(0) scale(1); } -} - -@keyframes toastSlideOut { - from { opacity: 1; transform: scale(1); } - to { opacity: 0; transform: scale(0.9); } -} - -/* ========================================================================== - Modern Confirm Modal - ========================================================================== */ -.custom-confirm-backdrop { - position: fixed; - inset: 0; - background: rgba(0,0,0,0.5); - z-index: 10001; - display: flex; - align-items: center; - justify-content: center; - backdrop-filter: blur(4px); - opacity: 0; -} - -.custom-confirm-modal { - background: var(--color-background-primary); - border: 1px solid var(--color-border-tertiary); - color: var(--color-text-primary); - opacity: 0; - transform: translateY(10px); -} - -@keyframes fadeIn { - to { opacity: 1; } -} - -@keyframes fadeOut { - to { opacity: 0; } -} - -@keyframes slideUp { - to { opacity: 1; transform: translateY(0); } -} - -@keyframes slideDown { - to { opacity: 0; transform: translateY(10px); } -} diff --git a/database.js b/database.js index 6fc7bec..d409373 100644 --- a/database.js +++ b/database.js @@ -3,56 +3,83 @@ const path = require('path'); const db = new sqlite3.Database(path.join(__dirname, 'studyplan.db')); -function initDb() { - db.serialize(() => { - // Subjects Table - db.run(`CREATE TABLE IF NOT EXISTS subjects ( - id TEXT PRIMARY KEY, - name TEXT NOT NULL, - short_code TEXT, - color TEXT, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP - )`); - - // Tasks Table - db.run(`CREATE TABLE IF NOT EXISTS tasks ( - id TEXT PRIMARY KEY, - subject_id TEXT, - title TEXT NOT NULL, - description TEXT, - due_at DATETIME, - status TEXT DEFAULT 'Not Started', - priority TEXT DEFAULT 'medium', - confidence_score REAL, - notes TEXT, - archived INTEGER DEFAULT 0, - labels TEXT DEFAULT '[]', - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (subject_id) REFERENCES subjects(id) - )`); - - // Add labels column to existing tasks table if it doesn't exist - db.all("PRAGMA table_info(tasks)", (err, rows) => { - if (err) return; - const hasLabels = rows.some(r => r.name === 'labels'); - if (!hasLabels) { - db.run("ALTER TABLE tasks ADD COLUMN labels TEXT DEFAULT '[]'"); - } +function dbRun(sql, params = []) { + return new Promise((resolve, reject) => { + db.run(sql, params, function (err) { + if (err) reject(err); + else resolve(this); }); + }); +} + +function dbGet(sql, params = []) { + return new Promise((resolve, reject) => { + db.get(sql, params, (err, row) => { + if (err) reject(err); + else resolve(row); + }); + }); +} - // Pre-populate some subjects if empty - db.get('SELECT COUNT(*) as count FROM subjects', (err, row) => { - if (row && row.count === 0) { - console.log("Seeding subjects..."); - const stmt = db.prepare("INSERT INTO subjects (id, name, short_code, color) VALUES (?, ?, ?, ?)"); - stmt.run('sub_1', 'Computer Science', 'CS', 'var(--color-text-info)'); - stmt.run('sub_2', 'Mathematics', 'Maths', 'var(--color-text-success)'); - stmt.run('sub_3', 'English Lit', 'English', 'var(--color-text-purple)'); - stmt.run('sub_4', 'Physics', 'Physics', 'var(--color-text-warning)'); - stmt.finalize(); - } +function dbAll(sql, params = []) { + return new Promise((resolve, reject) => { + db.all(sql, params, (err, rows) => { + if (err) reject(err); + else resolve(rows); }); }); } +async function initDb() { + // Create tables + await dbRun(`CREATE TABLE IF NOT EXISTS subjects ( + id TEXT PRIMARY KEY, + name TEXT NOT NULL, + short_code TEXT, + color TEXT, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP + )`); + + await dbRun(`CREATE TABLE IF NOT EXISTS tasks ( + id TEXT PRIMARY KEY, + subject_id TEXT, + title TEXT NOT NULL, + description TEXT, + due_at DATETIME, + status TEXT DEFAULT 'Not Started', + priority TEXT DEFAULT 'medium', + confidence_score REAL, + notes TEXT, + archived INTEGER DEFAULT 0, + labels TEXT DEFAULT '[]', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (subject_id) REFERENCES subjects(id) + )`); + + // Add labels column to existing tasks table if it doesn't exist + try { + const rows = await dbAll("PRAGMA table_info(tasks)"); + const hasLabels = rows.some(r => r.name === 'labels'); + if (!hasLabels) { + await dbRun("ALTER TABLE tasks ADD COLUMN labels TEXT DEFAULT '[]'"); + } + } catch (e) { + console.error('Migration error:', e.message); + } + + // Pre-populate some subjects if empty + try { + const row = await dbGet('SELECT COUNT(*) as count FROM subjects'); + if (row && row.count === 0) { + console.log("Seeding subjects..."); + await dbRun("INSERT INTO subjects (id, name, short_code, color) VALUES (?, ?, ?, ?)", ['sub_1', 'Computer Science', 'CS', 'var(--color-text-info)']); + await dbRun("INSERT INTO subjects (id, name, short_code, color) VALUES (?, ?, ?, ?)", ['sub_2', 'Mathematics', 'Maths', 'var(--color-text-success)']); + await dbRun("INSERT INTO subjects (id, name, short_code, color) VALUES (?, ?, ?, ?)", ['sub_3', 'English Lit', 'English', 'var(--color-text-purple)']); + await dbRun("INSERT INTO subjects (id, name, short_code, color) VALUES (?, ?, ?, ?)", ['sub_4', 'Physics', 'Physics', 'var(--color-text-warning)']); + } + } catch (e) { + console.error('Seed error:', e.message); + } +} + module.exports = { db, initDb }; diff --git a/index.html b/index.html index 3333d17..2b630d3 100644 --- a/index.html +++ b/index.html @@ -13,7 +13,7 @@
-