max / goingson
19 files changed,
+621 insertions,
-612 deletions
| @@ -134,6 +134,8 @@ pub struct TimelineDayData { | |||
| 134 | 134 | pub due_count: i32, | |
| 135 | 135 | /// Whether this day is marked as vacation | |
| 136 | 136 | pub is_vacation: bool, | |
| 137 | + | /// Events occurring on this day (capped at 5) | |
| 138 | + | pub events: Vec<EventSummary>, | |
| 137 | 139 | } | |
| 138 | 140 | ||
| 139 | 141 | /// Project health status for the weekly review. | |
| @@ -231,6 +233,7 @@ pub fn compute_weekly_review(input: WeeklyReviewInput) -> WeeklyReviewData { | |||
| 231 | 233 | &input.events_occurred, | |
| 232 | 234 | &input.tasks_overdue, | |
| 233 | 235 | &input.tasks_due_next_week, | |
| 236 | + | &input.upcoming_events, | |
| 234 | 237 | ); | |
| 235 | 238 | ||
| 236 | 239 | // Compute project health | |
| @@ -284,6 +287,7 @@ pub fn build_timeline_days( | |||
| 284 | 287 | events_occurred: &[Event], | |
| 285 | 288 | tasks_overdue: &[Task], | |
| 286 | 289 | tasks_due_next_week: &[Task], | |
| 290 | + | upcoming_events: &[Event], | |
| 287 | 291 | ) -> Vec<TimelineDayData> { | |
| 288 | 292 | let day_names = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; | |
| 289 | 293 | ||
| @@ -321,6 +325,14 @@ pub fn build_timeline_days( | |||
| 321 | 325 | 0 | |
| 322 | 326 | }; | |
| 323 | 327 | ||
| 328 | + | // Collect events for this day from both past and upcoming, capped at 5 | |
| 329 | + | let day_events: Vec<EventSummary> = events_occurred.iter() | |
| 330 | + | .chain(upcoming_events.iter()) | |
| 331 | + | .filter(|e| e.start_time >= day_start && e.start_time <= day_end) | |
| 332 | + | .take(5) | |
| 333 | + | .map(event_to_summary) | |
| 334 | + | .collect(); | |
| 335 | + | ||
| 324 | 336 | TimelineDayData { | |
| 325 | 337 | date: date.format("%Y-%m-%d").to_string(), | |
| 326 | 338 | day_name: day_names[day_offset as usize].to_string(), | |
| @@ -332,6 +344,7 @@ pub fn build_timeline_days( | |||
| 332 | 344 | overdue_count, | |
| 333 | 345 | due_count, | |
| 334 | 346 | is_vacation: vacation_days.contains(&(day_offset as u8)), | |
| 347 | + | events: day_events, | |
| 335 | 348 | } | |
| 336 | 349 | }) | |
| 337 | 350 | .collect() | |
| @@ -427,7 +440,7 @@ fn event_to_summary(event: &Event) -> EventSummary { | |||
| 427 | 440 | #[cfg(test)] | |
| 428 | 441 | mod tests { | |
| 429 | 442 | use super::*; | |
| 430 | - | use crate::id_types::{TaskId, UserId, WeeklyReviewId}; | |
| 443 | + | use crate::id_types::{EventId, TaskId, UserId, WeeklyReviewId}; | |
| 431 | 444 | use crate::models::{Priority, Recurrence}; | |
| 432 | 445 | use chrono::NaiveDate; | |
| 433 | 446 | ||
| @@ -507,7 +520,7 @@ mod tests { | |||
| 507 | 520 | fn test_build_timeline_days_count() { | |
| 508 | 521 | let week_start = NaiveDate::from_ymd_opt(2026, 2, 9).unwrap(); | |
| 509 | 522 | let today = NaiveDate::from_ymd_opt(2026, 2, 11).unwrap(); | |
| 510 | - | let days = build_timeline_days(week_start, today, &[], &[], &[], &[], &[]); | |
| 523 | + | let days = build_timeline_days(week_start, today, &[], &[], &[], &[], &[], &[]); | |
| 511 | 524 | assert_eq!(days.len(), 7); | |
| 512 | 525 | assert_eq!(days[0].day_name, "Mon"); | |
| 513 | 526 | assert_eq!(days[6].day_name, "Sun"); | |
| @@ -546,6 +559,7 @@ mod tests { | |||
| 546 | 559 | &[], | |
| 547 | 560 | &[], | |
| 548 | 561 | &[], | |
| 562 | + | &[], | |
| 549 | 563 | ); | |
| 550 | 564 | ||
| 551 | 565 | // Monday (index 0) should have 0 completions (task was created Monday but not completed then) | |
| @@ -583,6 +597,7 @@ mod tests { | |||
| 583 | 597 | &[], | |
| 584 | 598 | &[], | |
| 585 | 599 | &[], | |
| 600 | + | &[], | |
| 586 | 601 | ); | |
| 587 | 602 | ||
| 588 | 603 | // No day should count this task | |
| @@ -594,4 +609,92 @@ mod tests { | |||
| 594 | 609 | ); | |
| 595 | 610 | } | |
| 596 | 611 | } | |
| 612 | + | ||
| 613 | + | /// Creates a minimal event at the given time. | |
| 614 | + | fn make_event(title: &str, start_time: DateTime<Utc>) -> Event { | |
| 615 | + | Event { | |
| 616 | + | id: EventId::new(), | |
| 617 | + | user_id: None, | |
| 618 | + | project_id: None, | |
| 619 | + | project_name: None, | |
| 620 | + | contact_id: None, | |
| 621 | + | contact_name: None, | |
| 622 | + | title: title.to_string(), | |
| 623 | + | description: String::new(), | |
| 624 | + | start_time, | |
| 625 | + | end_time: None, | |
| 626 | + | location: None, | |
| 627 | + | linked_task_id: None, | |
| 628 | + | recurrence: Recurrence::None, | |
| 629 | + | recurrence_parent_id: None, | |
| 630 | + | block_type: None, | |
| 631 | + | } | |
| 632 | + | } | |
| 633 | + | ||
| 634 | + | #[test] | |
| 635 | + | fn test_build_timeline_days_with_events() { | |
| 636 | + | let week_start = NaiveDate::from_ymd_opt(2026, 2, 9).unwrap(); // Monday | |
| 637 | + | let today = NaiveDate::from_ymd_opt(2026, 2, 11).unwrap(); // Wednesday | |
| 638 | + | ||
| 639 | + | // Past event on Monday | |
| 640 | + | let mon_10am = NaiveDate::from_ymd_opt(2026, 2, 9).unwrap() | |
| 641 | + | .and_hms_opt(10, 0, 0) | |
| 642 | + | .map(|dt| DateTime::<Utc>::from_naive_utc_and_offset(dt, Utc)) | |
| 643 | + | .unwrap(); | |
| 644 | + | let mon_event = make_event("Monday standup", mon_10am); | |
| 645 | + | ||
| 646 | + | // Future event on Thursday | |
| 647 | + | let thu_14 = NaiveDate::from_ymd_opt(2026, 2, 12).unwrap() | |
| 648 | + | .and_hms_opt(14, 0, 0) | |
| 649 | + | .map(|dt| DateTime::<Utc>::from_naive_utc_and_offset(dt, Utc)) | |
| 650 | + | .unwrap(); | |
| 651 | + | let thu_event = make_event("Thursday meeting", thu_14); | |
| 652 | + | ||
| 653 | + | // Two events on Friday | |
| 654 | + | let fri_9 = NaiveDate::from_ymd_opt(2026, 2, 13).unwrap() | |
| 655 | + | .and_hms_opt(9, 0, 0) | |
| 656 | + | .map(|dt| DateTime::<Utc>::from_naive_utc_and_offset(dt, Utc)) | |
| 657 | + | .unwrap(); | |
| 658 | + | let fri_15 = NaiveDate::from_ymd_opt(2026, 2, 13).unwrap() | |
| 659 | + | .and_hms_opt(15, 0, 0) | |
| 660 | + | .map(|dt| DateTime::<Utc>::from_naive_utc_and_offset(dt, Utc)) | |
| 661 | + | .unwrap(); | |
| 662 | + | let fri_event1 = make_event("Friday morning", fri_9); | |
| 663 | + | let fri_event2 = make_event("Friday afternoon", fri_15); | |
| 664 | + | ||
| 665 | + | let events_occurred = vec![mon_event]; | |
| 666 | + | let upcoming_events = vec![thu_event, fri_event1, fri_event2]; | |
| 667 | + | ||
| 668 | + | let days = build_timeline_days( | |
| 669 | + | week_start, | |
| 670 | + | today, | |
| 671 | + | &[], | |
| 672 | + | &[], | |
| 673 | + | &events_occurred, | |
| 674 | + | &[], | |
| 675 | + | &[], | |
| 676 | + | &upcoming_events, | |
| 677 | + | ); | |
| 678 | + | ||
| 679 | + | // Monday (index 0): 1 event from events_occurred | |
| 680 | + | assert_eq!(days[0].events.len(), 1, "Monday should have 1 event"); | |
| 681 | + | assert_eq!(days[0].events[0].title, "Monday standup"); | |
| 682 | + | ||
| 683 | + | // Tuesday (index 1): no events | |
| 684 | + | assert_eq!(days[1].events.len(), 0, "Tuesday should have 0 events"); | |
| 685 | + | ||
| 686 | + | // Wednesday (index 2): no events | |
| 687 | + | assert_eq!(days[2].events.len(), 0, "Wednesday should have 0 events"); | |
| 688 | + | ||
| 689 | + | // Thursday (index 3): 1 event from upcoming | |
| 690 | + | assert_eq!(days[3].events.len(), 1, "Thursday should have 1 event"); | |
| 691 | + | assert_eq!(days[3].events[0].title, "Thursday meeting"); | |
| 692 | + | ||
| 693 | + | // Friday (index 4): 2 events from upcoming | |
| 694 | + | assert_eq!(days[4].events.len(), 2, "Friday should have 2 events"); | |
| 695 | + | ||
| 696 | + | // Saturday & Sunday: no events | |
| 697 | + | assert_eq!(days[5].events.len(), 0, "Saturday should have 0 events"); | |
| 698 | + | assert_eq!(days[6].events.len(), 0, "Sunday should have 0 events"); | |
| 699 | + | } | |
| 597 | 700 | } |
| @@ -1,6 +1,6 @@ | |||
| 1 | 1 | # GoingsOn Todo | |
| 2 | 2 | ||
| 3 | - | Done: All pre-beta phases + Phase 2 (Calendar Views) + maintenance cleanup. Active: Phase 9 (UX Polish, 9A done, 9B partially addressed by calendar restructure). Next: Phase 9 remainder, desktop distribution. | |
| 3 | + | Done: All pre-beta phases + Phase 2 (Calendar Views) + maintenance cleanup. Active: Phase 9 (UX Polish, 9A-9D done). Next: Phase 9 remainder, desktop distribution. | |
| 4 | 4 | ||
| 5 | 5 | v0.3.0, beta-ready. Audit grade A. 739 tests (691 Rust + 48 JS). Completed work archived in `docs/archive/go_todo_done.md`. | |
| 6 | 6 | ||
| @@ -46,8 +46,8 @@ v0.3.0, beta-ready. Audit grade A. 739 tests (691 Rust + 48 JS). Completed work | |||
| 46 | 46 | - [x] Frontend: monthly-review.js + monthly-review-render.js, API namespace, CSS | |
| 47 | 47 | ||
| 48 | 48 | ### Remaining | |
| 49 | - | - [ ] Week view: add upcoming events list below the existing weekly timeline visualizer | |
| 50 | - | - [ ] Week view: show events inline on the 7-day strip (not just dot counts) | |
| 49 | + | - [x] Week view: add upcoming events list below the existing weekly timeline visualizer | |
| 50 | + | - [x] Week view: show events inline on the 7-day strip (not just dot counts) | |
| 51 | 51 | ||
| 52 | 52 | --- | |
| 53 | 53 | ||
| @@ -135,7 +135,7 @@ Addressed by Phase 2 calendar restructure: Time tab now has 3 clear sub-views (D | |||
| 135 | 135 | ||
| 136 | 136 | - [x] Rename time pills: Day / Week / Month (clearer mental model) | |
| 137 | 137 | - [x] Remove Events/Calendar as a separate pill (events accessible via shortcuts, shown in Week view) | |
| 138 | - | - [ ] Update mobile nav dial to reflect new Day/Week/Month structure | |
| 138 | + | - [x] Update mobile nav dial to reflect new Day/Week/Month structure (replaced dial with bottom tab bar) | |
| 139 | 139 | - [ ] Consider removing Events from keyboard shortcut `v` (or redirect to Week view) | |
| 140 | 140 | ||
| 141 | 141 | (`navigation.js:11-26`, `index.html:206-210`) | |
| @@ -143,16 +143,16 @@ Addressed by Phase 2 calendar restructure: Time tab now has 3 clear sub-views (D | |||
| 143 | 143 | ### 9C: Postel's Law — Input Tolerance | |
| 144 | 144 | Make form inputs more forgiving of varied user input. | |
| 145 | 145 | ||
| 146 | - | - [ ] Date fields: accept natural text ("tomorrow", "next tuesday", "friday 3pm") via a lightweight parser, convert to `datetime-local` value | |
| 147 | - | - [ ] Tag input: auto-trim whitespace and normalize case | |
| 148 | - | - [ ] Search: strip leading/trailing whitespace before query | |
| 146 | + | - [x] Date fields: accept natural text ("tomorrow", "next tuesday", "friday 3pm") via a lightweight parser, convert to `datetime-local` value | |
| 147 | + | - [x] Tag input: auto-trim whitespace and normalize case | |
| 148 | + | - [x] Search: strip leading/trailing whitespace before query | |
| 149 | 149 | ||
| 150 | 150 | (`task-forms.js:49-147`, `utils.js:56-69`, `form-modal.js`) | |
| 151 | 151 | ||
| 152 | 152 | ### 9D: Serial Position Effect — Tab Order | |
| 153 | 153 | Verify most-used views occupy first and last positions. | |
| 154 | 154 | ||
| 155 | - | - [ ] Add anonymous usage tracking to `state.js` (count view switches per session, stored in memory only, not persisted) | |
| 155 | + | - [x] Add anonymous usage tracking to `state.js` (count view switches per session, stored in memory only, not persisted) | |
| 156 | 156 | - [ ] After a few weeks of personal use, review whether tab order matches actual usage frequency | |
| 157 | 157 | - [ ] If needed, reorder tabs in `index.html` to match usage (no code beyond the HTML edit) | |
| 158 | 158 |
| @@ -42,15 +42,7 @@ Tauri 2 iOS/Android port. CSS-first responsive design with touch gesture module. | |||
| 42 | 42 | - [x] All functions return cleanup functions, all are no-ops on non-touch devices | |
| 43 | 43 | ||
| 44 | 44 | ### Phase 3: Navigation + Bottom Sheets | |
| 45 | - | - [x] Floating nav dot (70px Skeubrute button, bottom-right) | |
| 46 | - | - [x] Radial petal dial (6 views: Projects, Tasks, Emails, Events, Daily, Weekly) | |
| 47 | - | - [x] Rectangular petal spokes with auto-computed radius (no overlap) | |
| 48 | - | - [x] 90° arc based on which corner the dot is nearest | |
| 49 | - | - [x] Petals rotated along spoke, flipped for readability | |
| 50 | - | - [x] Reverse z-order for natural fan overlap | |
| 51 | - | - [x] Center "+" button creates new item for current view | |
| 52 | - | - [x] Click handler (mouse) + touch handler (tap vs drag) | |
| 53 | - | - [x] Double-fire prevention (touch + synthesized click) | |
| 45 | + | - [x] ~~Floating nav dot + radial petal dial (replaced by bottom tab bar in Phase 6)~~ | |
| 54 | 46 | - [x] Action bottom sheets replace context menus on touch | |
| 55 | 47 | - [x] `showContextMenuSmart()` delegates to action sheet on touch, regular menu on desktop | |
| 56 | 48 | - [x] Modal swipe-to-dismiss wiring | |
| @@ -81,6 +73,17 @@ Tauri 2 iOS/Android port. CSS-first responsive design with touch gesture module. | |||
| 81 | 73 | - [x] Builds and runs on iOS simulator (iPhone 17 Pro, iOS 26.2) | |
| 82 | 74 | - [x] Safe area inset padding on header for iOS dynamic island | |
| 83 | 75 | ||
| 76 | + | ### Phase 6: Bottom Tab Bar (replaced nav dot/dial) | |
| 77 | + | - [x] Fixed bottom tab bar: Work / Time / Messages / + / More | |
| 78 | + | - [x] Context-aware "+" create button (creates item for current view) | |
| 79 | + | - [x] More popover: Settings + Shortcuts (replaces header buttons on mobile) | |
| 80 | + | - [x] `initMobileTabBar()` in `navigation.js`, tab switching via `data-view` | |
| 81 | + | - [x] Tab-to-view group mapping (`TAB_GROUPS`, `TAB_DEFAULTS`) | |
| 82 | + | - [x] Active tab highlighting synced with current view | |
| 83 | + | - [x] App header hidden on mobile (`display: none` at 768px) | |
| 84 | + | - [x] Body top padding for safe-area-inset-top (replaces header's notch spacing) | |
| 85 | + | - [x] Stale mobile header overrides removed (~15 lines: header-actions, settings-btn, app-subtitle, mobile-view-title) | |
| 86 | + | ||
| 84 | 87 | --- | |
| 85 | 88 | ||
| 86 | 89 | ## Remaining Work | |
| @@ -125,7 +128,7 @@ Tauri 2 iOS/Android port. CSS-first responsive design with touch gesture module. | |||
| 125 | 128 | |------|------| | |
| 126 | 129 | | `src-tauri/frontend/css/styles.css` | All responsive CSS (~400 lines of mobile rules) | | |
| 127 | 130 | | `src-tauri/frontend/js/touch.js` | Gesture utilities (~300 lines) | | |
| 128 | - | | `src-tauri/frontend/js/navigation.js` | Nav dot + radial dial | | |
| 131 | + | | `src-tauri/frontend/js/navigation.js` | Bottom tab bar + view switching | | |
| 129 | 132 | | `src-tauri/frontend/js/components.js` | Action sheets, modal swipe-dismiss | | |
| 130 | 133 | | `src-tauri/frontend/js/day-planning.js` | Tap-to-create, swipe day nav | | |
| 131 | 134 | | `src-tauri/frontend/js/events.js` | Mobile status indicator, date groups | |
| @@ -4099,6 +4099,63 @@ kbd { | |||
| 4099 | 4099 | border-radius: 2px; | |
| 4100 | 4100 | } | |
| 4101 | 4101 | ||
| 4102 | + | /* Day Events (inline on timeline strip) */ | |
| 4103 | + | .day-events { | |
| 4104 | + | display: flex; | |
| 4105 | + | flex-direction: column; | |
| 4106 | + | gap: 2px; | |
| 4107 | + | margin-top: 0.5rem; | |
| 4108 | + | text-align: left; | |
| 4109 | + | } | |
| 4110 | + | ||
| 4111 | + | .day-event { | |
| 4112 | + | font-size: 0.6rem; | |
| 4113 | + | line-height: 1.3; | |
| 4114 | + | padding: 1px 4px; | |
| 4115 | + | border-left: 2px solid var(--accent-purple); | |
| 4116 | + | white-space: nowrap; | |
| 4117 | + | overflow: hidden; | |
| 4118 | + | text-overflow: ellipsis; | |
| 4119 | + | color: var(--text-secondary); | |
| 4120 | + | } | |
| 4121 | + | ||
| 4122 | + | .day-event .event-time { | |
| 4123 | + | font-size: 0.55rem; | |
| 4124 | + | font-weight: 600; | |
| 4125 | + | color: var(--accent-purple); | |
| 4126 | + | margin-right: 2px; | |
| 4127 | + | min-width: auto; | |
| 4128 | + | } | |
| 4129 | + | ||
| 4130 | + | .day-event-more { | |
| 4131 | + | font-size: 0.55rem; | |
| 4132 | + | color: var(--text-muted); | |
| 4133 | + | padding: 1px 4px; | |
| 4134 | + | font-style: italic; | |
| 4135 | + | } | |
| 4136 | + | ||
| 4137 | + | /* Week's Events Card (below timeline) */ | |
| 4138 | + | .week-timeline-events { | |
| 4139 | + | grid-column: 1 / -1; | |
| 4140 | + | } | |
| 4141 | + | ||
| 4142 | + | .timeline-events-day { | |
| 4143 | + | margin-bottom: 0.75rem; | |
| 4144 | + | } | |
| 4145 | + | ||
| 4146 | + | .timeline-events-day:last-child { | |
| 4147 | + | margin-bottom: 0; | |
| 4148 | + | } | |
| 4149 | + | ||
| 4150 | + | .timeline-events-day-label { | |
| 4151 | + | font-family: var(--font-heading); | |
| 4152 | + | font-size: 0.8rem; | |
| 4153 | + | font-weight: 700; | |
| 4154 | + | color: var(--text-secondary); | |
| 4155 | + | margin-bottom: 0.25rem; | |
| 4156 | + | text-transform: uppercase; | |
| 4157 | + | } | |
| 4158 | + | ||
| 4102 | 4159 | /* Vacation Day Toggles */ | |
| 4103 | 4160 | .vacation-toggles-section { | |
| 4104 | 4161 | margin-top: 1rem; | |
| @@ -4480,6 +4537,7 @@ kbd { | |||
| 4480 | 4537 | } | |
| 4481 | 4538 | ||
| 4482 | 4539 | .week-timeline, | |
| 4540 | + | .week-timeline-events, | |
| 4483 | 4541 | .focus-section.full-width, | |
| 4484 | 4542 | .reflection-section { | |
| 4485 | 4543 | grid-column: 1; | |
| @@ -4635,7 +4693,8 @@ kbd { | |||
| 4635 | 4693 | ||
| 4636 | 4694 | .focus-section.full-width, | |
| 4637 | 4695 | .reflection-section, | |
| 4638 | - | .week-timeline { | |
| 4696 | + | .week-timeline, | |
| 4697 | + | .week-timeline-events { | |
| 4639 | 4698 | width: 100% !important; | |
| 4640 | 4699 | display: block !important; | |
| 4641 | 4700 | } | |
| @@ -5564,162 +5623,91 @@ button.milestone-reorder-btn.btn { | |||
| 5564 | 5623 | 58. Mobile Navigation (Nav Dot, Dial, Bottom Sheets) | |
| 5565 | 5624 | =================================================================== */ | |
| 5566 | 5625 | ||
| 5567 | - | /* --- Nav Dot (hidden on desktop) --- */ | |
| 5568 | - | .nav-dot { | |
| 5626 | + | /* --- Mobile Tab Bar (hidden on desktop, shown <=768px) --- */ | |
| 5627 | + | .mobile-tab-bar { | |
| 5569 | 5628 | display: none; | |
| 5570 | 5629 | position: fixed; | |
| 5571 | - | bottom: calc(20px + env(safe-area-inset-bottom, 0px)); | |
| 5572 | - | right: 20px; | |
| 5573 | - | width: 70px; | |
| 5574 | - | height: 70px; | |
| 5575 | - | border-radius: var(--radius-full); | |
| 5576 | - | background: var(--bg-card); | |
| 5577 | - | color: var(--text-primary); | |
| 5578 | - | border: var(--border-width) solid var(--border-color); | |
| 5630 | + | bottom: 0; | |
| 5631 | + | left: 0; | |
| 5632 | + | right: 0; | |
| 5579 | 5633 | z-index: 1100; | |
| 5634 | + | background: var(--bg-card); | |
| 5635 | + | border-top: var(--border-width) solid var(--border-color); | |
| 5636 | + | padding-bottom: env(safe-area-inset-bottom, 0px); | |
| 5637 | + | height: calc(52px + env(safe-area-inset-bottom, 0px)); | |
| 5638 | + | } | |
| 5639 | + | ||
| 5640 | + | .mobile-tab { | |
| 5641 | + | flex: 1; | |
| 5642 | + | display: flex; | |
| 5580 | 5643 | align-items: center; | |
| 5581 | 5644 | justify-content: center; | |
| 5582 | - | cursor: pointer; | |
| 5583 | - | user-select: none; | |
| 5584 | - | touch-action: none; | |
| 5585 | - | font-family: var(--font-display); | |
| 5586 | - | font-size: 1rem; | |
| 5645 | + | height: 52px; | |
| 5646 | + | background: none; | |
| 5647 | + | border: none; | |
| 5648 | + | color: var(--text-muted); | |
| 5649 | + | font-size: 0.7rem; | |
| 5587 | 5650 | font-weight: 700; | |
| 5651 | + | font-family: var(--font-sans); | |
| 5652 | + | text-transform: uppercase; | |
| 5588 | 5653 | letter-spacing: 0.05em; | |
| 5589 | - | transition: background-color 0.15s ease; | |
| 5590 | - | } | |
| 5591 | - | ||
| 5592 | - | .nav-dot:active { | |
| 5593 | - | background-color: var(--bg-tertiary); | |
| 5594 | - | } | |
| 5595 | - | ||
| 5596 | - | .nav-dot.dial-open { | |
| 5597 | - | background-color: var(--accent-blue); | |
| 5598 | - | color: var(--text-on-accent); | |
| 5654 | + | cursor: pointer; | |
| 5655 | + | -webkit-tap-highlight-color: transparent; | |
| 5656 | + | transition: color 0.15s ease; | |
| 5599 | 5657 | } | |
| 5600 | 5658 | ||
| 5601 | - | .nav-dot-icon { | |
| 5602 | - | pointer-events: none; | |
| 5659 | + | .mobile-tab.active { | |
| 5660 | + | color: var(--accent-blue); | |
| 5603 | 5661 | } | |
| 5604 | 5662 | ||
| 5605 | - | /* Status dots below the nav dot (mobile only) */ | |
| 5606 | - | .nav-dot-status { | |
| 5607 | - | display: none; | |
| 5608 | - | position: fixed; | |
| 5609 | - | bottom: calc(8px + env(safe-area-inset-bottom, 0px)); | |
| 5610 | - | right: 20px; | |
| 5611 | - | width: 70px; | |
| 5612 | - | z-index: 1100; | |
| 5613 | - | justify-content: center; | |
| 5614 | - | gap: 4px; | |
| 5615 | - | pointer-events: none; | |
| 5663 | + | .mobile-tab:active { | |
| 5664 | + | background: var(--bg-secondary); | |
| 5616 | 5665 | } | |
| 5617 | 5666 | ||
| 5618 | - | .nav-dot-status .tab-status-dot { | |
| 5619 | - | width: 10px; | |
| 5620 | - | height: 10px; | |
| 5621 | - | border-radius: 50%; | |
| 5622 | - | display: inline-block; | |
| 5623 | - | border: none; | |
| 5667 | + | .mobile-tab-create { | |
| 5668 | + | font-size: 1.4rem; | |
| 5669 | + | font-weight: 400; | |
| 5670 | + | color: var(--accent-green); | |
| 5671 | + | letter-spacing: 0; | |
| 5672 | + | text-transform: none; | |
| 5624 | 5673 | } | |
| 5625 | 5674 | ||
| 5626 | - | /* --- Nav Dial --- */ | |
| 5627 | - | .nav-dial { | |
| 5675 | + | /* --- More Popover --- */ | |
| 5676 | + | .mobile-more-popover { | |
| 5628 | 5677 | display: none; | |
| 5629 | 5678 | position: fixed; | |
| 5630 | - | z-index: 1099; | |
| 5631 | - | pointer-events: none; | |
| 5679 | + | bottom: calc(52px + env(safe-area-inset-bottom, 0px)); | |
| 5680 | + | right: 0; | |
| 5681 | + | background: var(--bg-card); | |
| 5682 | + | border: var(--border-width) solid var(--border-color); | |
| 5683 | + | border-radius: var(--radius-md); | |
| 5684 | + | padding: 0.25rem 0; | |
| 5685 | + | z-index: 1101; | |
| 5686 | + | min-width: 160px; | |
| 5687 | + | box-shadow: 0 -2px 8px rgba(0,0,0,0.1); | |
| 5632 | 5688 | } | |
| 5633 | 5689 | ||
| 5634 | - | .nav-dial.visible { | |
| 5690 | + | .mobile-more-popover.visible { | |
| 5635 | 5691 | display: block; | |
| 5636 | - | pointer-events: auto; | |
| 5637 | - | } | |
| 5638 | - | ||
| 5639 | - | .nav-dial.hidden { | |
| 5640 | - | display: none; | |
| 5641 | - | } | |
| 5642 | - | ||
| 5643 | - | .nav-dial-backdrop { | |
| 5644 | - | display: none; | |
| 5645 | - | position: fixed; | |
| 5646 | - | inset: 0; | |
| 5647 | - | background: rgba(0, 0, 0, 0.3); | |
| 5648 | - | z-index: 1098; | |
| 5649 | 5692 | } | |
| 5650 | 5693 | ||
| 5651 | - | .nav-dial-backdrop.visible { | |
| 5694 | + | .mobile-more-popover button { | |
| 5652 | 5695 | display: block; | |
| 5653 | - | } | |
| 5654 | - | ||
| 5655 | - | .nav-dial-item { | |
| 5656 | - | position: absolute; | |
| 5657 | - | width: 72px; | |
| 5658 | - | height: 28px; | |
| 5659 | - | border-radius: var(--radius-sm); | |
| 5660 | - | background: var(--bg-card); | |
| 5661 | - | border: var(--border-width) solid var(--border-color); | |
| 5662 | - | display: flex; | |
| 5663 | - | align-items: center; | |
| 5664 | - | justify-content: center; | |
| 5665 | - | font-size: 0.6rem; | |
| 5666 | - | font-weight: 700; | |
| 5696 | + | width: 100%; | |
| 5697 | + | padding: 0.75rem 1rem; | |
| 5698 | + | background: none; | |
| 5699 | + | border: none; | |
| 5700 | + | text-align: left; | |
| 5701 | + | font-size: var(--font-size-sm); | |
| 5702 | + | font-weight: 600; | |
| 5667 | 5703 | color: var(--text-primary); | |
| 5668 | 5704 | cursor: pointer; | |
| 5669 | - | opacity: 0; | |
| 5670 | - | transform-origin: center center; | |
| 5671 | - | transition: opacity 0.2s ease, background 0.15s ease, filter 0.15s ease; | |
| 5672 | - | } | |
| 5673 | - | ||
| 5674 | - | .nav-dial.visible .nav-dial-item { | |
| 5675 | - | opacity: 1; | |
| 5676 | - | /* transform (position + rotation) set by JS */ | |
| 5677 | 5705 | } | |
| 5678 | 5706 | ||
| 5679 | - | .nav-dial-item:hover { | |
| 5680 | - | filter: brightness(1.05); | |
| 5681 | - | } | |
| 5682 | - | ||
| 5683 | - | .nav-dial-item:active { | |
| 5684 | - | filter: brightness(0.95); | |
| 5685 | - | } | |
| 5686 | - | ||
| 5687 | - | .nav-dial-item.active { | |
| 5688 | - | background-color: var(--accent-blue); | |
| 5689 | - | color: var(--text-on-accent); | |
| 5690 | - | border-color: var(--border-color); | |
| 5691 | - | } | |
| 5692 | - | ||
| 5693 | - | .nav-dial-item.nav-dial-subitem { | |
| 5694 | - | font-size: 0.55rem; | |
| 5707 | + | .mobile-more-popover button:active { | |
| 5695 | 5708 | background: var(--bg-secondary); | |
| 5696 | 5709 | } | |
| 5697 | 5710 | ||
| 5698 | - | .nav-dial-item.nav-dial-subitem.active { | |
| 5699 | - | background-color: var(--accent-blue); | |
| 5700 | - | color: var(--text-on-accent); | |
| 5701 | - | } | |
| 5702 | - | ||
| 5703 | - | .nav-dial-item.nav-dial-center { | |
| 5704 | - | width: 44px; | |
| 5705 | - | height: 44px; | |
| 5706 | - | border-radius: var(--radius-full); | |
| 5707 | - | font-size: 1.25rem; | |
| 5708 | - | background-color: var(--accent-green); | |
| 5709 | - | color: var(--text-on-accent); | |
| 5710 | - | border-color: var(--border-color); | |
| 5711 | - | } | |
| 5712 | - | ||
| 5713 | - | .nav-dial-label { | |
| 5714 | - | pointer-events: none; | |
| 5715 | - | font-family: var(--font-sans); | |
| 5716 | - | text-transform: uppercase; | |
| 5717 | - | letter-spacing: 0.05em; | |
| 5718 | - | line-height: 1; | |
| 5719 | - | text-align: center; | |
| 5720 | - | white-space: nowrap; | |
| 5721 | - | } | |
| 5722 | - | ||
| 5723 | 5711 | /* --- Action Bottom Sheet --- */ | |
| 5724 | 5712 | .action-sheet { | |
| 5725 | 5713 | position: fixed; | |
| @@ -5914,32 +5902,22 @@ button.milestone-reorder-btn.btn { | |||
| 5914 | 5902 | =================================================================== */ | |
| 5915 | 5903 | ||
| 5916 | 5904 | @media (max-width: 768px) { | |
| 5917 | - | /* --- Safe area padding on body --- */ | |
| 5905 | + | /* --- Safe area padding + room for mobile tab bar --- */ | |
| 5918 | 5906 | body { | |
| 5919 | - | padding-bottom: env(safe-area-inset-bottom, 0px); | |
| 5907 | + | padding-top: env(safe-area-inset-top, 0px); | |
| 5908 | + | padding-bottom: calc(52px + env(safe-area-inset-bottom, 0px)); | |
| 5920 | 5909 | } | |
| 5921 | 5910 | ||
| 5922 | - | /* --- Hide desktop tab navigation, show nav dot --- */ | |
| 5923 | - | .tab-navigation { | |
| 5924 | - | display: none !important; | |
| 5925 | - | } | |
| 5926 | - | ||
| 5927 | - | .app-header { | |
| 5928 | - | padding: calc(0.5rem + env(safe-area-inset-top)) 1rem 0.5rem 1rem; | |
| 5929 | - | } | |
| 5930 | - | ||
| 5931 | - | .app-header .header-actions { | |
| 5911 | + | .mobile-tab-bar { | |
| 5932 | 5912 | display: flex; | |
| 5933 | - | flex-direction: column; | |
| 5934 | - | gap: 0.25rem; | |
| 5935 | 5913 | } | |
| 5936 | 5914 | ||
| 5937 | - | .app-header .header-actions .settings-btn { | |
| 5938 | - | font-size: 0.75rem; | |
| 5939 | - | padding: 0.3rem 0.6rem; | |
| 5915 | + | /* --- Hide desktop tab navigation --- */ | |
| 5916 | + | .tab-navigation { | |
| 5917 | + | display: none !important; | |
| 5940 | 5918 | } | |
| 5941 | 5919 | ||
| 5942 | - | .app-subtitle { | |
| 5920 | + | .app-header { | |
| 5943 | 5921 | display: none; | |
| 5944 | 5922 | } | |
| 5945 | 5923 | ||
| @@ -5959,26 +5937,6 @@ button.milestone-reorder-btn.btn { | |||
| 5959 | 5937 | display: none; | |
| 5960 | 5938 | } | |
| 5961 | 5939 | ||
| 5962 | - | .mobile-view-title { | |
| 5963 | - | display: inline; | |
| 5964 | - | font-size: 0.875rem; | |
| 5965 | - | color: var(--text-muted); | |
| 5966 | - | font-weight: 500; | |
| 5967 | - | line-height: 1; | |
| 5968 | - | } | |
| 5969 | - | ||
| 5970 | - | .nav-dot { | |
| 5971 | - | display: flex; | |
| 5972 | - | } | |
| 5973 | - | ||
| 5974 | - | .nav-dot-status { | |
| 5975 | - | display: flex; | |
| 5976 | - | } | |
| 5977 | - | ||
| 5978 | - | .nav-dot-status.dial-open { | |
| 5979 | - | display: none; | |
| 5980 | - | } | |
| 5981 | - | ||
| 5982 | 5940 | /* --- Main content adjustments --- */ | |
| 5983 | 5941 | .main-content { | |
| 5984 | 5942 | padding: 0.75rem; | |
| @@ -6044,7 +6002,7 @@ button.milestone-reorder-btn.btn { | |||
| 6044 | 6002 | /* --- Toast repositioning for mobile --- */ | |
| 6045 | 6003 | .toast, | |
| 6046 | 6004 | .toast-undo { | |
| 6047 | - | bottom: calc(env(safe-area-inset-bottom, 0px) + 5rem) !important; | |
| 6005 | + | bottom: calc(env(safe-area-inset-bottom, 0px) + 4.5rem) !important; | |
| 6048 | 6006 | left: 1rem !important; | |
| 6049 | 6007 | right: 1rem !important; | |
| 6050 | 6008 | max-width: none !important; |
| @@ -1 +1 @@ | |||
| 1 | - | @font-face{font-family:Reglo;src:url('../fonts/Reglo-Bold.woff2') format('woff2');font-weight:700;font-style:normal;font-display:swap}*,::after,::before{box-sizing:border-box;margin:0;padding:0}:root{--bg-primary:#E0E4FA;--bg-secondary:#CDD3F0;--bg-tertiary:#BAC2E6;--bg-card:#FFFFFF;--text-primary:#000000;--text-secondary:#2D2D2D;--text-muted:#6B6B6B;--accent-yellow:#F7D154;--accent-green:#5CB85C;--accent-blue:#6196FF;--accent-purple:#7B68EE;--accent-red:#DC3545;--accent-cyan:#17A2B8;--border-color:#000000;--border-width:2px;--border-width-sm:2px;--accent-color:var(--accent-blue);--accent-primary:var(--accent-blue);--bg-hover:var(--bg-tertiary);--border-light:var(--bg-tertiary);--text-on-accent:var(--bg-card);--shadow-offset-xs:1px;--shadow-offset-md:3px;--shadow-offset:4px;--shadow-offset-lg:6px;--shadow-offset-xl:8px;--shadow-brutal-xs:var(--shadow-offset-xs) var(--shadow-offset-xs) 0 var(--border-color);--shadow-brutal-md:var(--shadow-offset-md) var(--shadow-offset-md) 0 var(--border-color);--shadow-brutal-lg:var(--shadow-offset-lg) var(--shadow-offset-lg) 0 var(--border-color);--shadow-brutal-xl:var(--shadow-offset-xl) var(--shadow-offset-xl) 0 var(--border-color);--radius-xs:3px;--radius-sm:5px;--radius-md:5px;--radius-lg:10px;--radius-xl:20px;--radius-full:50%;--width-container:1400px;--width-modal:560px;--width-sidebar:280px;--space-1:0.25rem;--space-2:0.5rem;--space-3:0.75rem;--space-4:1rem;--space-5:1.25rem;--space-6:1.5rem;--font-sans:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;--font-serif:Georgia,'Times New Roman',serif;--font-mono:'SF Mono','Consolas','Liberation Mono',monospace;--font-display:'Reglo',var(--font-serif);--font-heading:var(--font-sans);--font-body:var(--font-sans);--font-size-xxs:0.65rem;--font-size-xs:0.7rem;--font-size-sm:0.75rem;--font-size-md:0.8rem;--font-size-base:0.875rem;--font-size-lg:1rem;--font-size-xl:1.1rem;--font-size-2xl:1.25rem;--font-size-3xl:1.5rem;--font-size-4xl:1.75rem;--line-height-tight:1.25;--line-height-normal:1.5;--line-height-relaxed:1.75;--transition-fast:0.1s;--transition-normal:0.15s;--transition-slow:0.3s;--overlay-color:color-mix(in srgb, var(--text-primary) 60%, transparent)}html{font-size:16px}.flex-1{flex:1}.flex-center-gap{display:flex;align-items:center;gap:.5rem}.text-sm-secondary{font-size:.875rem;color:var(--text-secondary)}.text-xs-secondary{font-size:.75rem;color:var(--text-secondary)}.text-accent-red{color:var(--accent-red)}.mb-1{margin-bottom:1rem}.settings-divider{margin-top:1.5rem;padding-top:1.5rem;border-top:2px solid var(--border-color)}.settings-heading{margin-bottom:1rem;font-family:var(--font-heading)}.settings-desc{font-size:.875rem;color:var(--text-secondary);margin-bottom:1rem}.subtask-item{display:flex;align-items:center;gap:.5rem;padding:.5rem;background:var(--bg-secondary);border-radius:4px;margin-bottom:.5rem}.subtask-item-linked{display:flex;align-items:center;gap:.5rem;padding:.5rem;background:var(--bg-tertiary);border-radius:4px;margin-bottom:.5rem;border-left:var(--border-width) solid var(--accent-color)}.subtask-checkbox{cursor:pointer;width:18px;height:18px}.subtask-checkbox-disabled{cursor:not-allowed;width:18px;height:18px;opacity:.5}.subtask-text-done{text-decoration:line-through;opacity:.6}body{font-family:var(--font-sans);background-color:var(--bg-primary);color:var(--text-primary);line-height:1.6;height:100vh;overflow:hidden;display:flex;flex-direction:column}.app-header{background:var(--bg-card);border-bottom:var(--border-width) solid var(--border-color);padding:.75rem 1.5rem;display:flex;justify-content:space-between;align-items:center}.header-content{display:flex;align-items:center;gap:.75rem}.header-actions{display:flex;align-items:center;gap:.5rem}.app-title{font-family:var(--font-display);font-size:1.75rem;font-weight:700;color:var(--text-primary);letter-spacing:-.02em}.app-subtitle{font-size:.875rem;color:var(--text-muted);font-weight:500;line-height:1}.mobile-view-title{display:none}.tab-navigation{display:flex;justify-content:center;gap:.5rem}.tab{display:flex;align-items:center;gap:.5rem;padding:.75rem 1.25rem;text-decoration:none;color:var(--text-primary);background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);font-weight:600;transition:background-color .15s ease}.tab:hover{background:var(--bg-secondary)}.tab.active{background-color:var(--accent-blue);color:var(--text-on-accent)}.tab-icon{font-size:1.1rem}.tab-label{font-weight:600;font-size:.9rem}.tab.tab-right{margin-left:auto}.tab-group .subview.hidden{display:none}.pill-nav{display:flex;align-items:center;gap:var(--space-1);padding:0;margin-bottom:1rem;min-height:2rem}.pill{padding:var(--space-1) var(--space-3);border-radius:var(--radius-xl);border:var(--border-width-sm) solid var(--border-color);background:var(--bg-card);font-family:var(--font-sans);font-size:var(--font-size-sm);font-weight:600;cursor:pointer;transition:background-color var(--transition-fast)}.pill:hover{background:var(--bg-tertiary)}.pill.active{background:var(--text-primary);color:var(--bg-card);border-color:var(--text-primary)}.main-content{flex:1;max-width:var(--width-container);width:100%;margin:0 auto;padding:1.5rem 1.75rem 2rem}.page-header{display:flex;justify-content:space-between;align-items:center;gap:.5rem;margin-bottom:1rem}.page-title{font-family:var(--font-heading);font-size:1.75rem;font-weight:700;color:var(--text-primary)}.tab-group{position:relative}.tab-group>.subview>.page-header{position:absolute;top:0;right:0;margin:0;z-index:1}.tab-group .page-header .page-title{display:none}#day-plan-view>.page-header,#project-dashboard-view>.page-header{position:static;margin-bottom:1rem}#project-dashboard-view .page-title{display:block}.btn{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;padding:.625rem 1.25rem;border:var(--border-width) solid var(--border-color);border-radius:var(--radius-sm);font-size:.9rem;font-weight:600;cursor:pointer;transition:background-color .15s ease;text-decoration:none;background:var(--bg-card);color:var(--text-primary)}.btn:hover{background:var(--bg-secondary)}.btn:active{background:var(--bg-tertiary)}.btn:disabled{background:var(--bg-tertiary);color:var(--text-muted);cursor:not-allowed;opacity:.7}.btn:disabled:hover{background:var(--bg-tertiary)}.btn-primary{background-color:var(--accent-blue);color:var(--text-on-accent)}.btn-primary:hover{background-color:color-mix(in srgb,var(--accent-blue) 85%,#000)}.btn-primary:active{background-color:color-mix(in srgb,var(--accent-blue) 70%,#000)}.btn-secondary{background-color:var(--bg-secondary);color:var(--text-primary)}.btn-danger{background-color:var(--accent-red);color:var(--text-on-accent)}.btn-danger:hover{background-color:color-mix(in srgb,var(--accent-red) 85%,#000)}.btn-danger:active{background-color:color-mix(in srgb,var(--accent-red) 70%,#000)}.btn-sm{padding:.375rem .75rem;font-size:.8rem}.quick-add{display:flex;gap:.75rem;margin-bottom:1.5rem}.quick-add-input{flex:1;padding:.875rem 1rem;border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);background-color:var(--bg-card);font-size:1rem;color:var(--text-primary)}.quick-add-input::placeholder{color:var(--text-muted)}.quick-add-input:focus{outline:0;background-color:var(--accent-blue);color:var(--text-on-accent);box-shadow:0 0 0 2px var(--border-color)}.cards-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:1.25rem}.card{background-color:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);padding:1.25rem;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color);transition:transform .15s ease,box-shadow .15s ease,background-color .15s ease;cursor:pointer}.card:hover{background-color:var(--bg-secondary);transform:translate(-2px,-2px);box-shadow:calc(var(--shadow-offset) + 2px) calc(var(--shadow-offset) + 2px) 0 var(--border-color)}.card-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:.75rem}.card-title{font-family:var(--font-heading);font-size:1.1rem;font-weight:700;color:var(--text-primary)}.card-description{font-size:.9rem;color:var(--text-secondary);margin-bottom:1rem}.markdown-content{font-size:.9rem;color:var(--text-secondary);line-height:1.5}.markdown-content p{margin:0 0 .5em 0}.markdown-content p:last-child{margin-bottom:0}.markdown-content ol,.markdown-content ul{margin:0 0 .5em 1.5em;padding:0}.markdown-content code{background:var(--bg-tertiary);padding:.1em .3em;border-radius:3px;font-size:.85em}.markdown-content pre{background:var(--bg-tertiary);padding:.5em;border-radius:4px;overflow-x:auto;margin:0 0 .5em 0}.markdown-content pre code{background:0 0;padding:0}.markdown-content a{color:var(--accent-color)}.markdown-content blockquote{border-left:3px solid var(--border-color);margin:0 0 .5em 0;padding-left:.75em;color:var(--text-secondary)}.markdown-content h1,.markdown-content h2,.markdown-content h3{margin:.5em 0 .25em 0;font-size:1em;font-weight:600;color:var(--text-primary)}.markdown-content table{border-collapse:collapse;margin:.5em 0}.markdown-content td,.markdown-content th{border:1px solid var(--border-color);padding:.25em .5em}.markdown-content img{max-width:100%}.card-meta{display:flex;gap:.5rem;flex-wrap:wrap}.badge,.tag{display:inline-flex;align-items:center;padding:.25rem .625rem;border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm);font-size:.8125rem;font-weight:600;background:var(--bg-card);color:var(--text-primary)}.badge[data-color=green],.tag[data-color=green]{background-color:color-mix(in srgb,var(--accent-green) 20%,var(--bg-card));border-color:var(--accent-green)}.badge[data-color=yellow],.tag[data-color=yellow]{background-color:color-mix(in srgb,var(--accent-yellow) 20%,var(--bg-card));border-color:var(--accent-yellow)}.badge[data-color=red],.tag[data-color=red]{background-color:color-mix(in srgb,var(--accent-red) 20%,var(--bg-card));border-color:var(--accent-red)}.badge[data-color=cyan],.tag[data-color=cyan]{background-color:color-mix(in srgb,var(--accent-cyan) 20%,var(--bg-card));border-color:var(--accent-cyan)}.badge[data-color=purple],.tag[data-color=purple]{background-color:color-mix(in srgb,var(--accent-purple) 20%,var(--bg-card));border-color:var(--accent-purple)}.badge[data-color=muted],.tag[data-color=muted]{background-color:var(--bg-tertiary);border-color:var(--text-muted)}.tag.status-active{background-color:color-mix(in srgb,var(--accent-green) 20%,var(--bg-card));border-color:var(--accent-green)}.tag.status-on_hold,.tag.status-onhold{background-color:color-mix(in srgb,var(--accent-yellow) 20%,var(--bg-card));border-color:var(--accent-yellow)}.tag.status-archived{background-color:var(--bg-tertiary);border-color:var(--text-muted)}.tag.status-inactive{background-color:color-mix(in srgb,var(--accent-red) 20%,var(--bg-card));border-color:var(--accent-red)}.tag.status-completed{background-color:color-mix(in srgb,var(--accent-cyan) 20%,var(--bg-card));border-color:var(--accent-cyan)}.data-table{width:100%;border-collapse:separate;border-spacing:0;background-color:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);overflow:hidden;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.data-table td,.data-table th{padding:1rem 1.25rem;text-align:left;border-bottom:2px solid var(--border-color)}.data-table th{background-color:var(--bg-secondary);font-size:.8rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--text-primary)}.data-table tbody tr{transition:background-color .15s ease}.data-table tbody tr:hover{background-color:var(--bg-secondary)}.data-table tbody tr:last-child td{border-bottom:none}.data-table tbody tr.keyboard-selected,.data-table tbody tr.selected{background-color:color-mix(in srgb,var(--accent-blue) 25%,var(--bg-card))}.task-table{width:100%;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-lg);overflow:hidden;display:flex;flex-direction:column;flex:1;min-height:0;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.task-header-row,.task-row{display:grid;grid-template-columns:1fr 140px 60px 110px 90px 100px 90px;align-items:center;gap:.75rem}.task-header-row{background-color:var(--bg-secondary);border-bottom:2px solid var(--border-color);padding:0 1.25rem}.task-header-row .task-cell{padding:.75rem 0;font-size:.8rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--text-primary)}.task-list-container{flex:1;min-height:0;overflow-y:auto;position:relative}.task-row{padding:.75rem 1.25rem;border-bottom:1px solid var(--border-color);transition:background-color .15s ease;cursor:pointer}.task-row:hover{background-color:var(--bg-secondary)}.task-row:last-child{border-bottom:none}.task-row.keyboard-selected,.task-row.selected{background-color:color-mix(in srgb,var(--accent-blue) 25%,var(--bg-card))}.task-cell{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.task-actions-header{text-align:right}.virtual-scroller-empty{padding:2rem;text-align:center;color:var(--text-secondary)}.event-table tbody tr{cursor:pointer}.task-description{font-weight:600;white-space:normal;display:flex;flex-wrap:wrap;align-items:center;gap:.25rem .5rem}.task-description-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}.task-project{font-size:.85rem;color:var(--text-secondary);white-space:nowrap}.priority-high,.priority-low,.priority-medium{display:inline-block;padding:.25rem .5rem;border-radius:var(--radius-xs);font-weight:700;text-align:center}.priority-high{color:var(--accent-red);background:#fde8ea;background:color-mix(in srgb,var(--accent-red) 15%,var(--bg-card))}.priority-medium{color:var(--accent-yellow);background:#fef8e6;background:color-mix(in srgb,var(--accent-yellow) 15%,var(--bg-card))}.priority-low{color:var(--text-muted);background:var(--bg-secondary)}.sortable{cursor:pointer;user-select:none;white-space:nowrap}.sortable:hover{background:var(--bg-hover)}.sort-arrow{display:inline-block;width:.8em;margin-left:.25rem;opacity:.3}.sort-arrow::after{content:'\2195'}.sortable.sort-asc .sort-arrow::after{content:'\2191'}.sortable.sort-desc .sort-arrow::after{content:'\2193'}.sortable.sort-asc .sort-arrow,.sortable.sort-desc .sort-arrow{opacity:1}.task-overdue .task-description-text{color:var(--accent-red)}.task-overdue .task-due{color:var(--accent-red);font-weight:600}.task-tags{display:flex;gap:.25rem;flex-wrap:wrap}.task-tag{background-color:var(--bg-tertiary);color:var(--text-primary);padding:.125rem .5rem;border-radius:var(--radius-xs);font-size:.75rem;font-weight:600;border:1px solid var(--border-color)}.recurrence-icon{color:var(--accent-purple);font-size:.85rem;font-weight:700}.annotation-badge{background-color:var(--accent-yellow);color:var(--text-primary);padding:.125rem .5rem;border-radius:var(--radius-xs);font-size:.7rem;font-weight:700;border:var(--border-width-sm) solid var(--border-color)}.subtask-badge{background-color:var(--bg-secondary);color:var(--text-primary);padding:.125rem .5rem;border-radius:var(--radius-xs);font-size:.7rem;font-weight:700;border:var(--border-width-sm) solid var(--border-color);margin-left:.25rem}.task-started{border-left:4px solid var(--accent-green)}.task-completed{opacity:.5;text-decoration:line-through}.task-deleted{display:none}.due-overdue{color:var(--accent-red);font-weight:700;background:#fde8ea;background:color-mix(in srgb,var(--accent-red) 15%,var(--bg-card));padding:.25rem .5rem;border-radius:var(--radius-xs)}.due-today{color:var(--accent-yellow);font-weight:700;background:#fef8e6;background:color-mix(in srgb,var(--accent-yellow) 15%,var(--bg-card));padding:.25rem .5rem;border-radius:var(--radius-xs)}.due-soon{color:var(--text-secondary)}.due-future{color:var(--text-muted)}.events-list{display:flex;flex-direction:column;flex:1;min-height:0;gap:1rem}.event-table-virtual{width:100%;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-lg);overflow:hidden;display:flex;flex-direction:column;flex:1;min-height:0;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.event-header-row,.event-row-virtual{display:grid;grid-template-columns:100px 80px 1fr 150px;align-items:center;gap:.5rem}.event-header-row{background-color:var(--bg-secondary);border-bottom:2px solid var(--border-color);flex-shrink:0}.event-header-row .event-cell{padding:1rem 1.25rem;font-size:.8rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--text-primary)}.event-list-container{flex:1;min-height:0;overflow-y:auto;position:relative}.event-row-virtual{padding:.75rem 1.25rem;border-bottom:1px solid var(--border-color);transition:background-color .15s ease;cursor:pointer}.event-row-virtual:hover{background-color:var(--bg-secondary)}.event-row-virtual:last-child{border-bottom:none}.event-row-virtual.event-past{opacity:.7}.event-cell{overflow:hidden;text-overflow:ellipsis}.event-row{cursor:pointer}.event-cell-date{white-space:nowrap}.event-cell-date .event-date-num{font-weight:700;font-size:.9rem;color:var(--text-primary);margin-right:.5rem}.event-date-badge{display:inline-block;padding:.15rem .4rem;background:var(--accent-green);color:var(--text-on-accent);font-size:.7rem;font-weight:700;text-transform:uppercase;border-radius:var(--radius-xs);margin-right:.5rem}.event-cell-time{font-family:var(--font-mono);font-size:.85rem;color:var(--text-secondary)}.event-cell-title{font-weight:600}.event-cell-location{color:var(--text-secondary);font-size:.875rem}.event-date-badge.event-proximity-today{background:var(--accent-green)}.event-date-badge.event-proximity-tomorrow{background:var(--accent-yellow);color:var(--text-primary)}.event-date-badge.event-proximity-week{background:var(--accent-cyan)}.event-date-badge.event-proximity-future{background:var(--accent-blue)}.event-date-badge.event-proximity-past{background:var(--text-muted)}.event-row.event-past{opacity:.7}.no-upcoming-events{text-align:center;padding:2rem;color:var(--text-secondary);font-style:italic}.past-events-section{margin-top:.5rem}.past-events-toggle{display:flex;align-items:center;gap:.75rem;padding:.75rem 1rem;background:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm);cursor:pointer;font-weight:600;color:var(--text-secondary);transition:background-color .15s ease,color .15s ease;list-style:none}.past-events-toggle::-webkit-details-marker{display:none}.past-events-toggle::before{content:'▶';font-size:.7rem;transition:transform .15s ease}.past-events-section[open] .past-events-toggle::before{transform:rotate(90deg)}.past-events-toggle:hover{background:var(--bg-tertiary);color:var(--text-primary)}.past-events-label{flex:1}.past-events-count{background:var(--text-muted);color:var(--text-on-accent);font-size:.75rem;padding:.15rem .5rem;border-radius:var(--radius-sm)}.past-events-section .event-table-past{margin-top:.75rem;opacity:.85}.past-events-section .event-list-container{max-height:300px}.event-item{display:flex;gap:1rem;padding:1rem;background-color:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);transition:background-color .15s ease;cursor:pointer}.event-item:hover{background-color:var(--bg-secondary)}.event-date{flex-shrink:0;width:80px;text-align:center;padding:.75rem;background-color:var(--accent-green);border-radius:var(--radius-sm);color:var(--text-on-accent)}.event-date-day{font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em}.event-date-num{font-size:1.5rem;font-weight:700}.event-content{flex:1}.event-title{font-family:var(--font-heading);font-weight:700;font-size:1.1rem;color:var(--text-primary);margin-bottom:.25rem}.event-details{font-size:.875rem;color:var(--text-secondary);display:flex;gap:1rem}.event-location,.event-time{display:flex;align-items:center;gap:.25rem}.event-project{margin-top:.5rem}.email-list{display:flex;flex-direction:column;background-color:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);overflow:hidden;flex:1;min-height:0;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.email-list-container{flex:1;min-height:0;overflow-y:auto;position:relative}.email-item{display:flex;gap:1rem;padding:1rem;border-bottom:2px solid var(--border-color);transition:background-color .15s ease;cursor:pointer}.email-item:last-child{border-bottom:none}.email-item:hover{background-color:var(--bg-secondary)}.email-item.unread{background-color:color-mix(in srgb,var(--accent-blue) 20%,var(--bg-card));border-left:4px solid var(--accent-blue)}.email-item.unread .email-subject{font-weight:700}.email-item.unread .email-from{font-weight:700}.email-item.outgoing{border-left:4px solid var(--accent-green)}.email-checkbox{flex-shrink:0;margin-top:.25rem}.email-content{flex:1;min-width:0}.email-header{display:flex;justify-content:space-between;margin-bottom:.25rem;align-items:center;gap:.5rem}.thread-badge{background-color:var(--bg-tertiary);color:var(--text-secondary);font-size:.7rem;font-weight:600;padding:.1rem .4rem;border-radius:var(--radius-md);min-width:1.25rem;text-align:center}.email-from{color:var(--text-primary);font-size:.9rem;font-weight:600}.email-date{color:var(--text-muted);font-size:.8rem;flex-shrink:0;font-weight:600}.email-subject{color:var(--text-primary);font-size:.95rem;margin-bottom:.25rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.email-preview{color:var(--text-muted);font-size:.85rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}@keyframes toastSlideIn{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.toast-undo{display:flex;align-items:center;gap:1rem}.undo-message{flex:1}.undo-btn{padding:.25rem .75rem;background:var(--accent-blue);color:var(--text-on-accent);border:2px solid var(--border-color);border-radius:var(--radius-sm);font-family:inherit;font-size:var(--font-size-sm);font-weight:600;cursor:pointer;transition:background .15s ease}.undo-btn:hover{background:color-mix(in srgb,var(--accent-blue) 80%,#000)}.undo-countdown{font-size:var(--font-size-sm);color:var(--text-muted);min-width:2.5rem;text-align:right}@keyframes modalFadeIn{from{opacity:0}to{opacity:1}}@keyframes modalSlideIn{from{opacity:0;transform:translateY(-20px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes modalFadeOut{from{opacity:1}to{opacity:0}}@keyframes modalSlideOut{from{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:translateY(-20px) scale(.95)}}.modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background-color:var(--overlay-color);display:flex;align-items:center;justify-content:center;z-index:1000;animation:modalFadeIn .15s ease-out}.modal-overlay.hidden{display:none}.modal-overlay.closing{animation:modalFadeOut .15s ease-in forwards}.modal-container{background-color:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-lg);box-shadow:var(--shadow-brutal-xl);max-width:var(--width-modal);width:90%;max-height:90vh;overflow:auto;animation:modalSlideIn .2s ease-out}.modal-container.modal-large{max-width:calc(100vw - 4rem);width:calc(100vw - 4rem);max-height:calc(100vh - 4rem);height:calc(100vh - 4rem);display:flex;flex-direction:column}.modal-container.modal-large .modal-content{flex:1;overflow:auto;display:flex;flex-direction:column}.modal-overlay.closing .modal-container{animation:modalSlideOut .15s ease-in forwards}.modal-header{display:flex;justify-content:space-between;align-items:center;padding:1rem 1.5rem;border-bottom:var(--border-width) solid var(--border-color);background:var(--bg-secondary)}.modal-header h2,.modal-title{font-family:var(--font-heading);font-size:1.25rem;font-weight:700}.modal-close{background:var(--bg-card);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm);font-size:1.25rem;color:var(--text-primary);cursor:pointer;line-height:1;width:36px;height:36px;display:flex;align-items:center;justify-content:center;transition:background-color .15s ease}.modal-close:hover{background:var(--accent-blue);color:var(--text-on-accent)}.modal-content{padding:1.5rem}.form-group{margin-bottom:1.25rem}.form-label{display:block;font-size:.9rem;font-weight:700;color:var(--text-primary);margin-bottom:.5rem}.form-input,.form-select,.form-textarea{width:100%;padding:.75rem 1rem;border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm);background-color:var(--bg-card);color:var(--text-primary);font-size:1rem;box-shadow:none}.form-input:focus,.form-select:focus,.form-textarea:focus{outline:0;background-color:var(--bg-card);box-shadow:0 0 0 2px var(--accent-blue)}.form-textarea{min-height:100px;resize:vertical}.form-actions{display:flex;justify-content:flex-end;gap:.75rem;margin-top:1.5rem}.form-input[aria-invalid=true],.form-select[aria-invalid=true],.form-textarea[aria-invalid=true]{border-color:var(--accent-red);box-shadow:0 0 0 2px color-mix(in srgb,var(--accent-red) 30%,transparent)}.form-input[aria-invalid=true]:focus,.form-select[aria-invalid=true]:focus,.form-textarea[aria-invalid=true]:focus{box-shadow:0 0 0 2px var(--accent-red)}.form-error{color:var(--accent-red);font-size:.8rem;font-weight:600;margin-top:.25rem;display:none}.form-error.visible{display:block}.app-footer{background-color:var(--bg-card);border-top:var(--border-width) solid var(--border-color);padding:.75rem 1.5rem}.footer-content{max-width:var(--width-container);margin:0 auto;display:flex;justify-content:space-between;align-items:center}.keyboard-hints{display:flex;gap:1rem;font-size:.8rem;color:var(--text-muted)}kbd{display:inline-block;padding:.2rem .5rem;background-color:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-xs);font-family:var(--font-mono);font-size:.75rem;font-weight:700}.version{font-size:.75rem;color:var(--text-muted);font-weight:600}.empty-state{text-align:center;padding:3rem;color:var(--text-secondary)}.empty-state-icon{font-size:4rem;margin-bottom:1rem}.empty-state-text{font-size:1.1rem;font-weight:600;margin-bottom:1rem}.error-state{text-align:center;padding:2rem;color:var(--accent-red);background:color-mix(in srgb,var(--accent-red) 10%,var(--bg-card));border:var(--border-width-sm) solid var(--accent-red);border-radius:var(--radius-sm);font-weight:600}.view{display:block}.view.hidden{display:none}.filter-bar{display:flex;flex-wrap:wrap;gap:.75rem;margin-bottom:1.5rem;padding:1rem;background-color:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.filter-group{display:flex;align-items:center;gap:.5rem}.filter-label{font-size:.8rem;font-weight:700;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.05em}.filter-select{padding:.5rem .75rem;border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm);background-color:var(--bg-card);color:var(--text-primary);font-size:.875rem;font-weight:600}.filter-select:focus{outline:0;background-color:var(--accent-blue);color:var(--text-on-accent)}.filter-checkbox{display:flex;align-items:center;gap:.4rem;font-size:.875rem;font-weight:600;color:var(--text-primary);cursor:pointer}.filter-checkbox input[type=checkbox]{width:1rem;height:1rem;cursor:pointer}.btn-link{background:0 0;border:none;box-shadow:none;color:var(--text-secondary);font-size:.875rem;cursor:pointer;text-decoration:underline;padding:.5rem}.btn-link:hover{box-shadow:none;transform:none;color:var(--text-primary)}@media (min-width:1400px){.main-content{max-width:1600px}.cards-grid{grid-template-columns:repeat(auto-fill,minmax(380px,1fr))}.project-dashboard-grid{gap:2rem}.day-plan-sidebar{width:320px}.modal-container{max-width:640px}}@media (max-width:1024px){.saved-views-sidebar{width:180px}.day-plan-sidebar{width:240px}.project-dashboard-grid{grid-template-columns:1fr 1fr;gap:1rem}.project-dashboard-grid .dashboard-column:last-child{grid-column:span 2}.filter-bar{flex-wrap:wrap}.filter-actions{width:100%;justify-content:flex-end;margin-top:.5rem}}@media (max-width:768px){.tab-navigation{flex-wrap:wrap;gap:.5rem}.tab{flex:1 1 auto;min-width:calc(33% - .5rem);justify-content:center;padding:.625rem .75rem}.tab-label{display:none}.tab-icon{font-size:1.25rem}.cards-grid{grid-template-columns:1fr}.task-table{font-size:.85rem}.task-header-row,.task-row{grid-template-columns:1fr 80px 40px 80px}.task-header-row .task-cell:nth-child(n+5),.task-row .task-cell:nth-child(n+5){display:none}.filter-bar{flex-direction:column}.keyboard-hints{display:none}.page-title{font-size:1.5rem}.saved-views-sidebar{display:none}.day-plan-content{flex-direction:column}.day-plan-sidebar{width:100%;max-height:200px}.project-dashboard-grid{grid-template-columns:1fr}.project-dashboard-grid .dashboard-column:last-child{grid-column:span 1}.modal-container{width:95%;max-height:95vh}.bulk-actions-bar{flex-wrap:wrap}.bulk-select-all{width:100%;margin-top:.5rem}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pagination-controls{display:flex;align-items:center;justify-content:center;gap:1rem;padding:1rem;margin-top:1rem;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md)}.pagination-info{font-weight:600;color:var(--text-secondary);font-size:.9rem}.pagination-controls .btn:disabled{opacity:.5;cursor:not-allowed}.btn:focus-visible,.card:focus-visible,.dashboard-item:focus-visible,.email-item:focus-visible,.event-row-virtual:focus-visible,.filter-select:focus-visible,.form-input:focus-visible,.form-select:focus-visible,.form-textarea:focus-visible,.modal-close:focus-visible,.saved-view-item:focus-visible,.snooze-option:focus-visible,.tab:focus-visible,.task-row:focus-visible,.timeline-item:focus-visible,.unscheduled-task:focus-visible{outline:3px solid var(--accent-blue);outline-offset:2px}.event-row,.task-row-clickable{cursor:pointer}.skip-link{position:absolute;top:-100px;left:0;background:var(--accent-blue);color:var(--text-on-accent);padding:.75rem 1.5rem;z-index:9999;font-weight:700;border:var(--border-width) solid var(--border-color);text-decoration:none}.skip-link:focus{top:0}.source-email-link{padding:.75rem;background:var(--bg-secondary);border-radius:var(--radius-sm);border-left:4px solid var(--accent-blue)}.thread-message{margin-bottom:1rem;padding:.75rem;background:var(--bg-secondary);border-radius:var(--radius-sm)}.thread-message-latest{border-left:3px solid var(--accent-blue)}.thread-message-header{display:flex;justify-content:space-between;margin-bottom:.5rem;font-size:.8rem;color:var(--text-secondary)}.thread-message-from{font-weight:700}.email-reader-body{white-space:pre-wrap;font-size:.9rem;line-height:1.6;color:var(--text-primary);word-wrap:break-word;overflow-wrap:break-word}.email-reader-body .email-link{color:var(--accent-blue);text-decoration:underline;cursor:pointer;word-break:break-all}.email-reader-body .email-link:hover{color:var(--accent-cyan)}.email-reader-body hr{border:none;border-top:2px solid var(--border-color);margin:1rem 0}.email-reader-quote{border-left:3px solid var(--text-muted);padding-left:1rem;margin:.5rem 0;color:var(--text-secondary);font-style:italic}.email-reader-container{display:flex;flex-direction:column;height:100%;min-height:0}.email-reader-header{margin-bottom:1rem;padding-bottom:.75rem;border-bottom:1px solid var(--border-color)}.email-sender-contact{display:flex;align-items:center;gap:.5rem;margin-top:.5rem;padding:.4rem .5rem;background:var(--bg-tertiary);border-radius:4px}.email-sender-info{display:flex;flex-direction:column;flex:1;min-width:0}.email-sender-name{font-weight:600;font-size:.85rem}.email-sender-company{font-size:.75rem;color:var(--text-secondary)}.contact-avatar-sm{width:32px;height:32px;border-radius:50%;background:var(--accent-color);color:var(--bg-primary);display:flex;align-items:center;justify-content:center;font-size:.75rem;font-weight:700;flex-shrink:0}.contact-avatar-unknown{background:var(--bg-secondary);color:var(--text-secondary);border:var(--border-width-sm) solid var(--border-color)}.email-reader-thread{flex:1;overflow-y:auto;margin-bottom:1rem;min-height:0}.dropdown{position:relative;display:inline-block}.dropdown-menu{display:none;position:absolute;bottom:100%;left:0;margin-bottom:.25rem;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);box-shadow:var(--shadow-brutal-md);min-width:160px;z-index:100}.dropdown-menu.show{display:block}.dropdown-item{display:block;width:100%;padding:.5rem 1rem;text-align:left;background:0 0;border:none;cursor:pointer;font-size:.875rem;color:var(--text-primary)}.dropdown-item:hover{background:var(--bg-secondary)}.dropdown-item:first-child{border-radius:var(--radius-md) var(--radius-md) 0 0}.dropdown-item:last-child{border-radius:0 0 var(--radius-md) var(--radius-md)}.context-menu{position:fixed;z-index:10000;min-width:180px;max-width:280px;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-sm);box-shadow:var(--shadow-brutal-lg);padding:.25rem 0;display:none}.context-menu.visible{display:block}.context-menu-item{display:flex;align-items:center;gap:.75rem;padding:.5rem 1rem;font-size:.875rem;font-weight:500;color:var(--text-primary);cursor:pointer;border:none;background:0 0;width:100%;text-align:left;transition:background .1s}.context-menu-item:focus,.context-menu-item:hover{background:var(--accent-blue);color:var(--text-on-accent);outline:0}.context-menu-item:focus-visible{outline:2px solid var(--accent-blue);outline-offset:-2px}.context-menu-item-icon{width:1.25rem;text-align:center;flex-shrink:0}.context-menu-item-label{flex:1}.context-menu-item-shortcut{font-size:.75rem;color:var(--text-muted);font-family:var(--font-mono)}.context-menu-item--danger{color:var(--accent-red)}.context-menu-item--danger:hover{background:var(--accent-red);color:var(--text-on-accent)}.context-menu-separator{height:2px;background:var(--border-color);margin:.25rem .5rem}.context-menu-hint{padding:.35rem 1rem;font-size:.7rem;color:var(--text-muted);border-top:1px solid var(--border-color);margin-top:.25rem}::-webkit-scrollbar{width:12px;height:12px}::-webkit-scrollbar-track{background:var(--bg-secondary);border-left:2px solid var(--border-color)}::-webkit-scrollbar-thumb{background:var(--text-muted);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm)}::-webkit-scrollbar-thumb:hover{background:var(--text-secondary)}.loading{display:flex;justify-content:center;align-items:center;height:200px;color:var(--text-secondary);font-family:var(--font-heading)}.skeleton-shimmer{display:flex;flex-direction:column;gap:1rem;padding:1rem}.skeleton-shimmer .skeleton-row{display:flex;align-items:center;gap:.75rem;padding:.75rem;background:var(--bg-card);border-radius:var(--radius-md);border:var(--border-width) solid var(--border-color)}.skeleton-shimmer .skeleton-avatar{width:36px;height:36px;border-radius:var(--radius-full);background:linear-gradient(90deg,var(--bg-secondary) 25%,var(--bg-tertiary) 50%,var(--bg-secondary) 75%);background-size:200% 100%;animation:skeleton-pulse 1.5s ease-in-out infinite;flex-shrink:0}.skeleton-shimmer .skeleton-lines{flex:1;display:flex;flex-direction:column;gap:.4rem}.skeleton-shimmer .skeleton-line{height:.75rem;border-radius:var(--radius-sm);background:linear-gradient(90deg,var(--bg-secondary) 25%,var(--bg-tertiary) 50%,var(--bg-secondary) 75%);background-size:200% 100%;animation:skeleton-pulse 1.5s ease-in-out infinite}.skeleton-shimmer .skeleton-line.short{width:40%}.skeleton-shimmer .skeleton-line.medium{width:65%}.skeleton-shimmer .skeleton-line.long{width:90%}@keyframes skeleton-pulse{0%{background-position:200% 0}100%{background-position:-200% 0}}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}.spinner{display:inline-block;width:1em;height:1em;border:2px solid currentColor;border-top-color:transparent;border-radius:var(--radius-full);animation:spin .8s linear infinite}.btn-loading{position:relative;pointer-events:none;opacity:.8}.btn-loading .btn-text{visibility:hidden}.btn-loading::after{content:'';position:absolute;left:50%;top:50%;width:1em;height:1em;margin-left:-.5em;margin-top:-.5em;border:2px solid currentColor;border-top-color:transparent;border-radius:var(--radius-full);animation:spin .8s linear infinite}.hidden{display:none!important}.project-dashboard-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1.5rem;flex:1;min-height:0}.dashboard-column{background:var(--bg-card);border:var(--border-width) solid var(--border-color);padding:1rem;display:flex;flex-direction:column;overflow:hidden}.dashboard-column-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem;padding-bottom:.5rem;border-bottom:2px solid var(--border-color)}.dashboard-column-header h3{margin:0;font-size:1rem;font-family:var(--font-heading);font-weight:700}.dashboard-list{flex:1;overflow-y:auto}.dashboard-item{padding:.75rem;background:var(--bg-card);border:var(--border-width-sm) solid var(--border-color);margin-bottom:.5rem;cursor:pointer;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color);transition:transform .15s ease,box-shadow .15s ease,background-color .15s ease}.dashboard-item:hover{background:var(--bg-secondary);transform:translate(-2px,-2px);box-shadow:calc(var(--shadow-offset) + 2px) calc(var(--shadow-offset) + 2px) 0 var(--border-color)}.dashboard-item-title{font-weight:600;margin-bottom:.25rem}.dashboard-item-meta{font-size:.75rem;color:var(--text-secondary)}.empty-dashboard-list{text-align:center;padding:2rem 1rem;color:var(--text-secondary)}.task-badges{display:flex;gap:.25rem;margin-top:.25rem}.task-badge{font-size:.65rem;padding:.15rem .4rem;border:var(--border-width-sm) solid var(--border-color);background:var(--bg-secondary);color:var(--text-primary);font-weight:600}.task-badge.has-items{background:var(--accent-blue);color:var(--text-on-accent)}.task-badge.recurrence{background:var(--accent-purple);color:var(--text-on-accent)}.task-row-clickable{cursor:pointer;transition:background .1s}.task-row-clickable:hover{background:var(--bg-secondary)}.progress-bar-container{width:100%;height:10px;background:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);overflow:hidden}.progress-bar{height:100%;background:var(--accent-green);transition:width .3s ease}.no-subtasks{color:var(--text-secondary);font-size:.875rem}#day-plan-view{display:flex;flex-direction:column;flex:1;min-height:0}#day-plan-view .page-header{flex-shrink:0}.day-plan-nav{display:flex;align-items:center;gap:.5rem}.day-plan-date-picker{padding:.5rem;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-sm);color:var(--text-primary);font-family:var(--font-body)}.day-plan-date-display{font-size:1.25rem;font-weight:700;margin-left:1rem;font-family:var(--font-heading);line-height:1}.day-plan-content{flex:1;min-height:0;display:flex;gap:1.5rem}.day-plan-main{flex:1;min-height:0;display:flex;flex-direction:column;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);overflow:hidden;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.day-plan-sidebar{width:280px;flex-shrink:0;display:flex;flex-direction:column;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);overflow:hidden;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.sidebar-header{padding:1rem;border-bottom:2px solid var(--border-color);flex-shrink:0}.sidebar-header h3{margin:0;font-size:1rem;font-family:var(--font-heading);font-weight:700}.sidebar-task-list{flex:1;overflow-y:auto;padding:.75rem;display:flex;flex-direction:column;gap:.5rem}.timeline-container{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden}.timeline-scroll-area{position:relative;padding:.5rem 1rem 3rem .5rem;min-height:min-content}#timeline-slots{position:relative}#timeline-items{position:absolute;top:.5rem;left:.5rem;right:1rem;bottom:0;pointer-events:none}#timeline-items .timeline-item{pointer-events:auto}.timeline-slot{display:grid;grid-template-columns:50px 1fr;height:12px;position:relative}.timeline-slot.hour-start .timeline-slot-area{border-top:1px dashed color-mix(in srgb,var(--border-color) 50%,transparent)}.timeline-time{font-size:.7rem;color:var(--text-secondary);padding-right:.5rem;text-align:right;font-weight:500;transform:translateY(-.5em)}.timeline-slot-area{position:relative}.timeline-slot-area:hover{background:var(--bg-secondary)}.timeline-item{position:absolute;left:60px;right:10px;border:var(--border-width) solid var(--border-color);border-radius:var(--radius-sm);padding:.25rem .5rem;overflow:hidden;cursor:pointer;z-index:10}.timeline-item.task{background:var(--accent-green);color:var(--text-primary)}.timeline-item.event{background:var(--accent-blue);color:var(--text-on-accent)}.timeline-item.block{opacity:.85}.timeline-item.block-free_time{background:var(--accent-cyan);color:var(--text-primary)}.timeline-item.block-personal{background:var(--accent-yellow);color:var(--text-primary)}.timeline-item.block-vacation{background:var(--accent-purple);color:var(--text-on-accent)}.timeline-item.block-focus{background:var(--accent-red);color:var(--text-on-accent)}.timeline-item.conflict{box-shadow:0 0 0 3px var(--accent-red)}.timeline-item.selected{box-shadow:0 0 0 3px var(--bg-card),0 0 0 6px var(--accent-blue)}.timeline-item-title{font-weight:600;font-size:.75rem;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.timeline-item-meta{font-size:.65rem;opacity:.85;line-height:1.1}.timeline-current-time{position:absolute;left:50px;right:0;height:2px;background:var(--accent-red);z-index:20;pointer-events:none}.timeline-current-time::before{content:'';position:absolute;left:-4px;top:-3px;width:8px;height:8px;background:var(--accent-red);border-radius:var(--radius-full)}.timeline-paint-preview{position:absolute;left:70px;right:10px;background:var(--accent-blue);opacity:.4;border:var(--border-width-sm) dashed var(--border-color);border-radius:var(--radius-sm);z-index:5;pointer-events:none}.timeline-container.is-painting{cursor:crosshair;user-select:none}.timeline-container.is-painting .timeline-slot-area{pointer-events:none}.unscheduled-task{padding:.75rem;background:var(--bg-card);border:var(--border-width-sm) solid var(--border-color);border-left:6px solid var(--accent-green);border-radius:var(--radius-sm);cursor:grab;transition:background-color .1s}.unscheduled-task:hover{background:var(--bg-secondary)}.unscheduled-task.priority-high{border-left-color:var(--accent-red)}.unscheduled-task.priority-medium{border-left-color:var(--accent-yellow)}.unscheduled-task.priority-low{border-left-color:var(--accent-green)}.unscheduled-task-title{font-weight:600;margin-bottom:.25rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.unscheduled-task-meta{font-size:.75rem;color:var(--text-secondary)}.empty-unscheduled{text-align:center;color:var(--text-secondary);padding:2rem 1rem}.settings-btn{background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-sm);color:var(--text-primary);font-size:1.25rem;cursor:pointer;padding:.5rem .75rem;margin-left:.5rem;transition:background-color .1s}.settings-btn:hover{background:var(--bg-secondary)}.settings-btn:active{background:var(--bg-tertiary)}.shortcut-hint-btn{font-family:var(--font-mono, monospace);font-weight:700;min-width:2rem;text-align:center;padding:.5rem}.settings-section h3{font-size:1rem;color:var(--text-primary)}.settings-section .form-hint{font-size:.75rem;color:var(--text-secondary)}.llm-settings-form .form-group{margin-bottom:1rem}.llm-settings-form .form-row{display:grid;grid-template-columns:1fr 1fr;gap:1rem}.llm-settings-form .form-hint{font-size:.75rem;color:var(--text-secondary);margin-top:.25rem}.llm-settings-form .slider-value{font-weight:700;color:var(--accent-blue)}.llm-test-result{padding:.75rem;border:var(--border-width) solid var(--border-color);margin-top:1rem}.llm-test-result.success{background:var(--accent-green);color:var(--text-primary)}.llm-test-result.error{background:var(--accent-red);color:var(--text-on-accent)}.llm-cache-info{margin-top:1rem;padding-top:1rem;border-top:2px solid var(--border-color)}.sync-indicator{background:0 0;border:none;cursor:pointer;padding:.25rem .5rem;display:flex;align-items:center}.sync-dot{width:8px;height:8px;border-radius:var(--radius-full);background:var(--text-muted);transition:background var(--transition-slow)}.sync-dot.connected{background:var(--accent-green)}.sync-dot.syncing{background:var(--accent-blue);animation:sync-pulse 1s infinite}.sync-dot.error{background:var(--accent-red)}@keyframes sync-pulse{0%,100%{opacity:1}50%{opacity:.4}}.snooze-options{display:flex;flex-direction:column;gap:.5rem}.snooze-option{display:flex;justify-content:space-between;align-items:center;padding:.75rem 1rem;background:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);color:var(--text-primary);cursor:pointer;transition:background-color .1s;text-align:left;width:100%}.snooze-option:hover{background:var(--accent-blue);color:var(--text-on-accent)}.snooze-option-label{font-weight:600}.snooze-option-time{font-size:.75rem;color:var(--text-secondary)}.snooze-option:hover .snooze-option-time{color:var(--text-on-accent)}.snooze-custom{margin-top:.5rem;padding-top:.5rem;border-top:2px solid var(--border-color)}.snooze-badge{display:inline-block;font-size:.65rem;padding:.15rem .4rem;border:var(--border-width-sm) solid var(--border-color);background:var(--accent-yellow);color:var(--text-primary);font-weight:700;margin-top:.25rem}.contact-badge{display:inline-block;font-size:.65rem;padding:.15rem .4rem;border:var(--border-width-sm) solid var(--border-color);background:var(--accent-color);color:var(--bg-primary);font-weight:700;margin-top:.25rem}.bulk-checkbox{width:18px;height:18px;cursor:pointer;accent-color:var(--accent-blue);border:var(--border-width-sm) solid var(--border-color)}.task-actions-cell{text-align:right;white-space:nowrap;display:flex;align-items:center;justify-content:flex-end;gap:.5rem}.task-actions-cell .bulk-checkbox{margin-right:.5rem}.task-recurrence{font-size:.85rem;color:var(--text-secondary)}.task-due{white-space:nowrap}.bulk-actions-bar{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem;background:var(--accent-blue);color:var(--text-on-accent);border:var(--border-width) solid var(--border-color);box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color);margin-bottom:1rem;color:var(--text-primary)}.bulk-actions-bar.hidden{display:none}.bulk-count{font-weight:700;margin-right:1rem;font-family:var(--font-heading)}.bulk-actions-bar .btn{background:var(--bg-card);border:var(--border-width-sm) solid var(--border-color);color:var(--text-primary)}.bulk-actions-bar .btn:hover{background:var(--bg-secondary)}.bulk-select-all{margin-left:auto}.email-checkbox-cell{padding:.75rem .5rem;display:flex;align-items:center}.email-item-with-checkbox{display:flex;align-items:flex-start}.email-item-with-checkbox .email-content{flex:1}.schedule-task-btn{display:flex;align-items:center;gap:.5rem}.time-block-form{display:flex;flex-direction:column;gap:1rem}.time-block-quick-options{display:grid;grid-template-columns:repeat(3,1fr);gap:.5rem}.time-block-quick-btn{padding:.5rem;background:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);color:var(--text-primary);cursor:pointer;font-size:.875rem;font-weight:600;transition:background-color .1s}.time-block-quick-btn:hover{background:var(--bg-tertiary)}.time-block-quick-btn.selected{background:var(--accent-blue);color:var(--text-on-accent);box-shadow:inset 0 0 0 2px var(--border-color)}.duration-presets{display:flex;gap:.5rem;flex-wrap:wrap}.duration-preset{padding:.35rem .75rem;background:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);color:var(--text-primary);cursor:pointer;font-size:.75rem;font-weight:600;transition:background-color .1s}.duration-preset:hover{background:var(--bg-tertiary)}.duration-preset.selected{background:var(--accent-blue);color:var(--text-on-accent)}.conflict-warning{padding:.75rem;background:var(--accent-red);border:var(--border-width) solid var(--border-color);color:var(--text-on-accent);font-size:.875rem;font-weight:600;margin-top:.5rem}.app-body{display:flex;flex:1;min-height:0;overflow:hidden}.app-body .main-content{flex:1;min-width:0;display:flex;flex-direction:column;overflow-x:visible;overflow-y:auto}#emails-view,#events-view,#projects-view,#tasks-view{padding-bottom:2.5rem}#tasks-view{display:flex;flex-direction:column;flex:1;min-height:0}#tasks-view .bulk-actions-bar,#tasks-view .filter-bar,#tasks-view .page-header{flex-shrink:0}#events-view{display:flex;flex-direction:column;flex:1;min-height:0}#events-view .page-header{flex-shrink:0}#emails-view{display:flex;flex-direction:column;flex:1;min-height:0}#emails-view .bulk-actions-bar,#emails-view .page-header{flex-shrink:0}.saved-views-sidebar{width:200px;flex-shrink:0;background:var(--bg-card);border-right:var(--border-width) solid var(--border-color);display:flex;flex-direction:column;overflow:hidden}.sidebar-section{display:flex;flex-direction:column;flex:1;min-height:0}.sidebar-section-header{display:flex;justify-content:space-between;align-items:center;padding:.75rem 1rem;font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--text-secondary);border-bottom:2px solid var(--border-color);background:var(--bg-secondary)}.btn-icon{background:0 0;border:none;color:var(--text-muted);cursor:pointer;padding:.25rem;font-size:.875rem;line-height:1}.btn-icon:hover{color:var(--text-primary)}.pinned-views-list{flex:1;overflow-y:auto;padding:.5rem}.sidebar-empty{text-align:center;padding:1.5rem .5rem;color:var(--text-muted);font-size:.8rem}.saved-view-item{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;margin-bottom:.5rem;background:var(--bg-card);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm);cursor:pointer;font-size:.85rem;font-weight:600;color:var(--text-primary);box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color);transition:transform .15s ease,box-shadow .15s ease,background-color .15s ease,color .15s ease}.saved-view-item:hover{background:var(--accent-blue);color:var(--text-on-accent)}.saved-view-item.active{background:var(--accent-blue);color:var(--text-on-accent);box-shadow:inset 0 0 0 2px var(--border-color)}.saved-view-item .view-icon{font-size:.75rem}.saved-view-item .view-name{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.saved-view-item .view-actions{opacity:0;transition:opacity .1s}.saved-view-item:hover .view-actions{opacity:1}.filter-actions{display:flex;gap:.5rem;margin-left:auto}.contact-avatar{width:40px;height:40px;min-width:40px;border-radius:50%;background-color:var(--accent-blue);color:var(--text-on-accent);display:flex;align-items:center;justify-content:center;font-weight:700;font-size:.85rem;font-family:var(--font-heading);border:2px solid var(--border-color)}.contact-avatar-lg{width:60px;height:60px;min-width:60px;font-size:1.2rem}.contact-card .card-header{display:flex;align-items:center}.contact-nickname{display:block;font-size:.85rem;color:var(--text-secondary);font-style:italic}.contact-company{display:block;font-size:.85rem;color:var(--text-secondary)}.contact-email{font-size:.85rem;color:var(--text-secondary)}.contact-detail .detail-row{margin-bottom:.5rem;font-size:.9rem}.contact-detail .contact-info-section{margin-bottom:1rem;padding-bottom:1rem;border-bottom:1px solid var(--border-light,#e0e0e0)}.contact-detail .contact-notes{margin-bottom:1.5rem}.contact-detail .contact-notes p{margin-top:.25rem;white-space:pre-wrap;color:var(--text-secondary)}.sub-collection{margin-bottom:1.25rem}.sub-collection-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.5rem}.sub-collection-header h4{margin:0;font-size:.95rem;font-weight:600}.sub-item{display:flex;justify-content:space-between;align-items:center;padding:.4rem 0;border-bottom:1px solid var(--border-light,#e0e0e0);font-size:.9rem}.sub-item:last-child{border-bottom:none}.sub-empty{font-size:.85rem;color:var(--text-secondary);font-style:italic;padding:.25rem 0}.edit-sub-collections{border-top:1px solid var(--border-color);padding-top:1rem;margin-bottom:.5rem}.edit-sub-section{margin-bottom:.75rem}.edit-sub-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.25rem}.sub-item-compact{font-size:.85rem;color:var(--text-secondary);padding:.125rem 0}@media print{.btn,.context-menu,.filter-bar,.keyboard-hints,.modal-overlay,.pagination,.sidebar,.tabs,.toast{display:none!important}body{background:#fff;color:#000}.main-content{margin:0;padding:0;max-width:100%}.view{padding:0}.data-table{border:1px solid #333;box-shadow:none}.data-table td,.data-table th{border:1px solid #ccc;padding:.5rem}.data-table td,.data-table th{display:table-cell!important}.data-table tbody tr:hover{background:0 0}.task-table{border:1px solid #333;box-shadow:none}.task-list-container{height:auto!important;overflow:visible!important}.task-header-row,.task-row{grid-template-columns:1fr 100px 40px 80px 60px 80px 60px!important}.task-header-row .task-cell,.task-row .task-cell{display:block!important;border:1px solid #ccc;padding:.25rem .5rem}.task-row:hover{background:0 0}.virtual-scroller-spacer-bottom,.virtual-scroller-spacer-top{display:none!important}a{color:#000;text-decoration:underline}.view-header{page-break-after:avoid}.data-table{page-break-inside:avoid}}.weekly-review-content{max-width:900px;margin:0 auto;padding:1rem}.weekly-review-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1.5rem;padding-bottom:1rem;border-bottom:var(--border-width-sm) solid var(--border-color)}.week-info{display:flex;align-items:center;gap:1rem}.week-dates{font-family:var(--font-heading);font-size:1.25rem;font-weight:700;color:var(--text-primary)}.review-status{padding:.25rem .75rem;border-radius:var(--radius-xs);font-size:.875rem;font-weight:600;border:var(--border-width-sm) solid var(--border-color)}.review-status.completed{background:var(--accent-green);color:var(--text-on-accent)}.review-status.pending{background:var(--accent-yellow);color:var(--text-primary)}.stat-cards{display:flex;gap:1rem;margin-bottom:1rem;flex-wrap:wrap}.stat-card{flex:1;min-width:100px;max-width:150px;padding:1rem;background:var(--bg-card);border:var(--border-width) solid var(--border-color);text-align:center;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.stat-card .stat-number{display:block;font-family:var(--font-heading);font-size:2rem;font-weight:700;color:var(--accent-blue);line-height:1}.stat-card .stat-label{display:block;font-size:.75rem;font-weight:600;color:var(--text-muted);margin-top:.25rem;text-transform:uppercase;letter-spacing:.5px}.stat-card.stat-warning .stat-number{color:var(--accent-yellow)}.stat-card.stat-danger .stat-number{color:var(--accent-red)}.review-section{background:var(--bg-card);border:var(--border-width) solid var(--border-color);padding:1.25rem;margin-bottom:1.5rem;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.section-title{font-family:var(--font-heading);font-size:1.125rem;font-weight:700;color:var(--text-primary);margin-bottom:1rem;padding-bottom:.5rem;border-bottom:var(--border-width-sm) solid var(--border-color)}.review-details{margin-top:.75rem}.review-details summary{cursor:pointer;font-weight:600;color:var(--text-secondary);padding:.5rem;background:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);user-select:none}.review-details summary:hover{background:var(--bg-tertiary)}.review-details[open] summary{margin-bottom:.5rem}.review-event-list,.review-task-list{list-style:none;padding:0;margin:0}.review-event-item,.review-task-item{display:flex;align-items:center;gap:.75rem;padding:.5rem .75rem;border-bottom:1px solid var(--border-color)}.review-event-item:last-child,.review-task-item:last-child{border-bottom:none}.review-event-item .event-title,.review-task-item .task-description{flex:1;color:var(--text-primary)}.event-time{font-size:.875rem;font-weight:600;color:var(--text-muted);min-width:80px}.project-badge{font-size:.75rem;padding:.125rem .5rem;background:var(--bg-tertiary);border:1px solid var(--border-color);color:var(--text-secondary)}.due-badge{font-size:.75rem;padding:.125rem .5rem;background:var(--bg-secondary);border:1px solid var(--border-color);color:var(--text-secondary)}.due-badge.overdue{background:var(--accent-red);color:var(--text-on-accent);border-color:var(--accent-red)}.focus-section{background:linear-gradient(135deg,var(--bg-card) 0,color-mix(in srgb,var(--accent-yellow) 15%,var(--bg-card)) 100%)}.focus-task-list{list-style:none;padding:0;margin:0 0 1rem 0}.focus-task-list.available{opacity:.8}.focus-toggle{background:0 0;border:none;font-size:1.25rem;cursor:pointer;color:var(--text-muted);padding:0;line-height:1;transition:transform .15s ease}.focus-toggle:hover{transform:scale(1.2)}.focus-toggle.focused{color:var(--accent-yellow)}.review-task-item.focused{background:color-mix(in srgb,var(--accent-yellow) 10%,var(--bg-card))}.no-focus-message{color:var(--text-muted);font-style:italic;margin-bottom:1rem}.focused-projects{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}.project-tag{background:var(--accent-blue);color:var(--text-on-accent);padding:.25rem .75rem;font-size:.875rem;font-weight:600;border:var(--border-width-sm) solid var(--border-color)}.notes-section{background:var(--bg-card)}.review-notes-input{width:100%;padding:.75rem;font-family:var(--font-mono);font-size:.9rem;border:var(--border-width-sm) solid var(--border-color);background:var(--bg-secondary);color:var(--text-primary);resize:vertical;min-height:100px}.review-notes-input:focus{outline:0;background:var(--bg-card);box-shadow:inset 0 0 0 2px var(--accent-blue)}.review-actions{margin-top:1rem;text-align:center}.tab-badge{display:inline-block;width:8px;height:8px;background:var(--accent-red);border-radius:var(--radius-full);margin-left:.5rem;vertical-align:middle;animation:pulse-badge 2s infinite}@keyframes pulse-badge{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.6;transform:scale(.8)}}.tab-status-dot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-left:.5rem;vertical-align:middle;transition:background-color .3s ease}.tab-status-dot.status-none{display:none}.tab-status-dot.status-green{background-color:var(--accent-green)}.tab-status-dot.status-yellow{background-color:var(--accent-yellow);animation:pulse-badge 2s ease-in-out infinite}.tab-status-dot.status-red{background-color:var(--accent-red);animation:pulse-badge 1.5s ease-in-out infinite}.review-grid{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem;max-width:1200px;margin:0 auto}.review-card{background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);padding:1.5rem;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.review-card .card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem;padding-bottom:.75rem;border-bottom:var(--border-width-sm) solid var(--bg-secondary)}.review-card .card-title{font-family:var(--font-heading);font-size:1.1rem;font-weight:700;display:flex;align-items:center;gap:.5rem}.review-card .card-icon{font-size:1.25rem}.review-card .card-badge{font-size:.8rem;padding:.25rem .75rem;border-radius:var(--radius-md);font-weight:600}.week-timeline{grid-column:1/-1}.timeline-visual{display:flex;gap:.5rem;margin-top:1rem}.timeline-day{flex:1;text-align:center;padding:.75rem .5rem;background:var(--bg-secondary);border-radius:var(--radius-md);border:1px solid var(--border-color);position:relative}.timeline-day.today{background:var(--accent-blue);color:var(--text-on-accent);border-width:2px;font-weight:700}.timeline-day.past{opacity:.7}.timeline-day.future{background:var(--bg-card)}.timeline-day .day-name{font-size:.7rem;font-weight:600;text-transform:uppercase;color:var(--text-muted)}.timeline-day .day-number{font-size:1.1rem;font-weight:700}.day-dots{display:flex;justify-content:center;gap:3px;margin-top:.5rem;min-height:8px}.day-dot{width:8px;height:8px;border-radius:var(--radius-full)}.day-dot.task{background:var(--accent-blue)}.day-dot.event{background:var(--accent-purple)}.day-dot.completed{background:var(--accent-green)}.day-dot.overdue{background:var(--accent-red)}.day-dot.vacation-off{background:var(--text-muted);opacity:.5;width:12px;height:4px;border-radius:2px}.vacation-toggles-section{margin-top:1rem;padding-top:1rem;border-top:2px solid var(--border-color)}.vacation-toggles-section h3{margin:0 0 .75rem 0;font-size:.9rem;font-family:var(--font-heading);font-weight:700}.vacation-toggles{display:flex;gap:.5rem}.vacation-toggle{width:2.5rem;height:2.5rem;border-radius:var(--radius-sm);border:var(--border-width) solid var(--border-color);background:var(--bg-secondary);font-family:var(--font-heading);font-weight:700;font-size:.8rem;cursor:pointer;transition:background var(--transition-fast),color var(--transition-fast),border-color var(--transition-fast);display:flex;align-items:center;justify-content:center}.vacation-toggle:hover{background:var(--bg-hover)}.vacation-toggle.active{background:var(--accent-purple);color:var(--text-on-accent);border-color:var(--accent-purple)}.timeline-day.vacation{opacity:.5}.timeline-day.vacation .day-name{text-decoration:line-through}.vacation-day-banner{text-align:center;padding:.5rem 1rem;background:color-mix(in srgb,var(--accent-purple) 15%,var(--bg-secondary));border:var(--border-width-sm) solid var(--accent-purple);border-radius:var(--radius-sm);font-family:var(--font-heading);font-weight:700;font-size:.85rem;color:var(--accent-purple);margin-bottom:.75rem}.stats-row{display:flex;gap:1rem;margin-bottom:1rem}.stat-box{flex:1;text-align:center;padding:1rem;background:var(--bg-secondary);border-radius:var(--radius-md)}.stat-box .stat-number{font-family:var(--font-heading);font-size:2rem;font-weight:800;line-height:1}.stat-box .stat-number.green{color:var(--accent-green)}.stat-box .stat-number.red{color:var(--accent-red)}.stat-box .stat-number.blue{color:var(--accent-blue)}.stat-box .stat-number.purple{color:var(--accent-purple)}.stat-box .stat-label{font-size:.75rem;text-transform:uppercase;color:var(--text-muted);font-weight:600;margin-top:.25rem}.task-list{list-style:none;max-height:200px;overflow-y:auto}.task-item{display:flex;align-items:center;gap:.75rem;padding:.75rem;margin-bottom:.5rem;background:var(--bg-secondary);border-radius:var(--radius-md);cursor:pointer;transition:background-color var(--transition-normal)}.task-item:hover{background:var(--accent-blue);color:var(--text-on-accent)}.task-item.completed{opacity:.6;text-decoration:line-through}.task-checkbox{width:20px;height:20px;border:2px solid var(--border-color);border-radius:var(--radius-xs);display:flex;align-items:center;justify-content:center;flex-shrink:0}.task-checkbox.checked{background:var(--accent-green);color:var(--text-on-accent)}.task-text{flex:1;font-size:.9rem}.task-project{font-size:.75rem;padding:.2rem .5rem;background:var(--bg-card);border-radius:var(--radius-xs);color:var(--text-muted)}.task-due{font-size:.75rem;color:var(--text-muted)}.task-due.overdue{color:var(--accent-red);font-weight:600}.focus-section.full-width{grid-column:1/-1}.focus-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:1rem;margin-top:1rem}.focus-slot{padding:1.25rem;background:var(--bg-secondary);border:2px dashed var(--border-color);border-radius:var(--radius-md);min-height:100px;display:flex;flex-direction:column;gap:.5rem}.focus-slot.filled{border-style:solid;background:var(--bg-card)}.focus-slot.primary{border-color:var(--accent-yellow);background:linear-gradient(135deg,var(--bg-card) 0,color-mix(in srgb,var(--accent-yellow) 10%,var(--bg-card)) 100%)}.focus-label{font-size:.7rem;text-transform:uppercase;color:var(--text-muted);font-weight:600}.focus-task{font-weight:600;font-size:.95rem}.focus-meta{font-size:.8rem;color:var(--text-secondary)}.focus-empty{color:var(--text-muted);font-style:italic;font-size:.9rem}.projects-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;margin-top:.5rem}.project-health{padding:.75rem;background:var(--bg-secondary);border-radius:var(--radius-md);border-left:4px solid var(--accent-blue)}.project-health.warning{border-left-color:var(--accent-yellow)}.project-health.danger{border-left-color:var(--accent-red)}.project-name{font-weight:600;font-size:.85rem;margin-bottom:.25rem}.project-stats{font-size:.75rem;color:var(--text-muted)}.reflection-section{grid-column:1/-1}.reflection-prompts{display:grid;grid-template-columns:1fr 1fr;gap:1rem;margin-top:1rem}.reflection-prompt{padding:1rem;background:var(--bg-secondary);border-radius:var(--radius-md)}.prompt-label{font-size:.8rem;font-weight:600;color:var(--text-secondary);margin-bottom:.5rem}.prompt-input{width:100%;padding:.75rem;border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-md);font-size:.9rem;font-family:inherit;resize:none;background:var(--bg-card)}.prompt-input:focus{outline:0;border-color:var(--accent-blue)}.review-actions-grid{grid-column:1/-1;display:flex;justify-content:flex-end;gap:1rem;padding-top:1rem}.event-item{display:flex;align-items:center;gap:.75rem;padding:.75rem;margin-bottom:.5rem;background:var(--bg-secondary);border-radius:var(--radius-md);border-left:3px solid var(--accent-purple)}.event-item .event-time{font-size:.8rem;font-weight:600;color:var(--accent-purple);min-width:100px}.event-item .event-title{flex:1;font-size:.9rem}.accomplishment-highlight{background:linear-gradient(135deg,color-mix(in srgb,var(--accent-green) 10%,var(--bg-card)) 0,color-mix(in srgb,var(--accent-green) 5%,var(--bg-card)) 100%);border:2px solid var(--accent-green);padding:1rem;border-radius:var(--radius-md);margin-bottom:1rem;display:flex;align-items:center;gap:1rem}.accomplishment-icon{font-size:2rem}.accomplishment-text{font-size:1rem}.accomplishment-text strong{color:var(--accent-green)}.task-list::-webkit-scrollbar{width:6px}.task-list::-webkit-scrollbar-track{background:var(--bg-secondary);border-radius:var(--radius-xs)}.task-list::-webkit-scrollbar-thumb{background:var(--border-color);border-radius:var(--radius-xs)}@media (max-width:900px){.review-grid{grid-template-columns:1fr}.focus-section.full-width,.reflection-section,.week-timeline{grid-column:1}.focus-grid{grid-template-columns:1fr}.reflection-prompts{grid-template-columns:1fr}.projects-grid{grid-template-columns:1fr 1fr}}@media (max-width:600px){.stat-cards{flex-direction:column}.stat-card{max-width:none}.week-info{flex-direction:column;align-items:flex-start;gap:.5rem}.projects-grid{grid-template-columns:1fr}}.focus-slot{transition:background-color .2s ease-out,border-color .2s ease-out}.focus-slot.filled{animation:focusSlotFill .3s ease-out}@keyframes focusSlotFill{0%{transform:scale(.95);opacity:.7}100%{transform:scale(1);opacity:1}}.focus-slot:focus,.focus-slot:focus-within{outline:2px solid var(--accent-blue);outline-offset:2px}.focus-slot[tabindex]:focus{outline:2px solid var(--accent-blue);outline-offset:2px}.focus-section .btn{transition:transform .15s ease-out,opacity .15s ease-out}.focus-section .btn:active{transform:scale(.97)}@media print{.card-badge,.focus-section .btn,.focus-slot .btn,.header,.review-actions-grid,.sidebar,.tab-badge,.tab-nav,.tab-status-dot{display:none!important}.main-content,.weekly-review-content{margin:0;padding:0;width:100%;max-width:100%}.event-item,.focus-slot,.project-health,.reflection-prompt,.review-card,.weekly-review-content,body{background:#fff!important;color:#000!important;-webkit-print-color-adjust:exact;print-color-adjust:exact}.review-card{border:1px solid #ccc!important;box-shadow:none!important;page-break-inside:avoid;margin-bottom:1rem}.focus-slot{border:1px solid #999!important}.focus-slot.primary{border:2px solid #f7d154!important;background:#fffbea!important}.review-grid{display:block!important}.review-card{display:inline-block;vertical-align:top;width:48%;margin-right:2%}.focus-section.full-width,.reflection-section,.week-timeline{width:100%!important;display:block!important}.weekly-review-header{border-bottom:2px solid #333;padding-bottom:1rem;margin-bottom:1.5rem}.week-dates{font-size:1.5rem;font-weight:700}.day-dot{-webkit-print-color-adjust:exact;print-color-adjust:exact}.day-dot.completed{background:#5cb85c!important}.day-dot.event{background:#9b59b6!important}.day-dot.overdue{background:#d9534f!important}.project-health{border-left:4px solid #337ab7!important}.project-health.warning{border-left-color:#f7d154!important}.project-health.danger{border-left-color:#d9534f!important}.focus-grid{display:flex!important;gap:1rem}.focus-slot{flex:1}.reflection-prompts{display:flex!important;gap:1rem}.reflection-prompt{flex:1}.prompt-input{border:1px solid #ccc!important;min-height:80px}.focus-section{page-break-before:auto}.reflection-section{page-break-before:always}}.monthly-review-nav{display:flex;align-items:center;gap:.5rem}.monthly-review-month-display{font-family:var(--font-heading);font-size:1.25rem;font-weight:700;color:var(--text-primary);margin-left:.5rem}.monthly-review-content{max-width:900px;margin:0 auto;padding:1rem}.month-heatmap{margin-bottom:1.5rem;border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-md);padding:1rem;background:var(--bg-secondary)}.month-heatmap-header{display:grid;grid-template-columns:repeat(7,1fr);text-align:center;margin-bottom:.5rem}.month-heatmap-day-header{font-family:var(--font-heading);font-size:.75rem;font-weight:600;color:var(--text-secondary);text-transform:uppercase}.month-heatmap-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:3px}.month-heatmap-cell{aspect-ratio:1;display:flex;flex-direction:column;align-items:center;justify-content:center;border-radius:var(--radius-xs);cursor:pointer;transition:transform .1s ease;border:var(--border-width-sm) solid transparent;position:relative;min-height:40px}.month-heatmap-cell:not(.empty):hover{transform:scale(1.1);border-color:var(--border-color);z-index:1}.month-heatmap-cell.empty{cursor:default;background:0 0}.month-heatmap-cell.intensity-0{background:var(--bg-primary)}.month-heatmap-cell.intensity-1{background:color-mix(in srgb,var(--accent-green) 20%,var(--bg-primary))}.month-heatmap-cell.intensity-2{background:color-mix(in srgb,var(--accent-green) 40%,var(--bg-primary))}.month-heatmap-cell.intensity-3{background:color-mix(in srgb,var(--accent-green) 60%,var(--bg-primary))}.month-heatmap-cell.vacation{background:var(--bg-tertiary);opacity:.6}.month-heatmap-cell.today{border-color:var(--accent-primary);border-width:2px}.month-heatmap-cell.past.intensity-0{background:var(--bg-tertiary)}.month-heatmap-day-number{font-family:var(--font-heading);font-size:.8rem;font-weight:600;color:var(--text-primary)}.month-heatmap-dots{display:flex;gap:2px;margin-top:2px}.month-dot{font-size:.6rem;font-weight:700;border-radius:var(--radius-xs);padding:0 3px;line-height:1.3}.month-dot.completed{color:var(--accent-green)}.month-dot.event{color:var(--accent-purple)}.monthly-review-cards{display:grid;grid-template-columns:1fr 1fr;gap:1rem}.review-card.month-goals-card,.review-card.month-stats-card{grid-column:span 1}.review-card.month-patterns-card,.review-card.month-pulse-card{grid-column:span 1}.review-card.month-reflection-card{grid-column:1/-1}.review-card-title{font-family:var(--font-heading);font-size:1rem;font-weight:700;margin-bottom:.75rem;color:var(--text-primary)}.month-stats-grid{display:grid;grid-template-columns:1fr 1fr;gap:.5rem}.month-stat-item{display:flex;flex-direction:column;align-items:center;padding:.5rem;border-radius:var(--radius-xs);background:var(--bg-primary);border:var(--border-width-sm) solid var(--border-color)}.month-stat-value{font-family:var(--font-heading);font-size:1.5rem;font-weight:700;color:var(--text-primary)}.month-stat-label{font-size:.75rem;color:var(--text-secondary);text-transform:uppercase;font-weight:600}.month-stats-highlights{display:flex;gap:1rem;margin-top:.5rem;justify-content:center}.stat-highlight{font-size:.8rem;color:var(--text-secondary)}.month-pulse-list{display:flex;flex-direction:column;gap:.5rem}.month-pulse-item{display:flex;align-items:center;gap:.5rem;padding:.5rem;border-radius:var(--radius-xs);background:var(--bg-primary);border:var(--border-width-sm) solid var(--border-color)}.pulse-name{font-weight:600;flex:1;font-size:.875rem}.pulse-stats{font-size:.75rem;color:var(--text-secondary)}.pulse-arrow{font-size:1rem;font-weight:700}.month-pulse-item.positive .pulse-arrow{color:var(--accent-green)}.month-pulse-item.negative .pulse-arrow{color:var(--accent-red)}.month-pulse-item.neutral .pulse-arrow{color:var(--text-secondary)}.month-goals-list{display:flex;flex-direction:column;gap:.5rem}.month-goal-item{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;border-radius:var(--radius-xs);background:var(--bg-primary);border:var(--border-width-sm) solid var(--border-color)}.month-goal-item.empty{cursor:pointer;border-style:dashed;justify-content:center}.month-goal-item.empty:hover{border-color:var(--accent-primary);background:var(--bg-secondary)}.month-goal-item.done{opacity:.7}.month-goal-item.done .month-goal-text{text-decoration:line-through}.month-goal-item.abandoned{opacity:.5}.month-goal-item.abandoned .month-goal-text{text-decoration:line-through}.month-goal-status-btn{background:0 0;border:none;cursor:pointer;font-size:1rem;padding:0;color:var(--text-secondary);width:24px;text-align:center}.month-goal-item.done .month-goal-status-btn{color:var(--accent-green)}.month-goal-item.abandoned .month-goal-status-btn{color:var(--accent-red)}.month-goal-text{flex:1;font-size:.875rem}.month-goal-delete-btn{background:0 0;border:none;cursor:pointer;color:var(--text-tertiary);padding:0 4px;font-size:.75rem;opacity:0;transition:opacity .15s}.month-goal-item:hover .month-goal-delete-btn{opacity:1}.month-goal-placeholder{color:var(--text-tertiary);font-size:.875rem}.month-reflection-fields{display:flex;flex-direction:column;gap:.5rem}.month-reflection-label{font-size:.875rem;font-weight:600;color:var(--text-secondary)}.month-reflection-textarea{width:100%;padding:.5rem;border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-xs);background:var(--bg-primary);color:var(--text-primary);font-family:var(--font-body);font-size:.875rem;resize:vertical}.month-reflection-textarea:focus{outline:2px solid var(--accent-primary);outline-offset:-1px}.month-patterns-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:.5rem}.month-pattern-item{font-size:.875rem;color:var(--text-secondary);padding:.5rem;background:var(--bg-primary);border-radius:var(--radius-xs);border:var(--border-width-sm) solid var(--border-color)}@media (max-width:640px){.monthly-review-cards{grid-template-columns:1fr}.review-card.month-goals-card,.review-card.month-patterns-card,.review-card.month-pulse-card,.review-card.month-stats-card{grid-column:span 1}.month-heatmap-cell{min-height:32px}.month-heatmap-day-number{font-size:.7rem}.month-heatmap-dots{display:none}}.import-wizard{display:flex;flex-direction:column;gap:1.5rem}.import-step{padding:1rem;background:var(--bg-secondary);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md)}.import-step h3{margin:0 0 1rem 0;font-size:var(--font-size-md);font-weight:600}.plugin-selector{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:.75rem}.plugin-option{display:flex;flex-direction:column;align-items:flex-start;padding:.75rem 1rem;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-sm);cursor:pointer;text-align:left;transition:border-color var(--transition-fast),background var(--transition-fast)}.plugin-option:hover{border-color:var(--accent-primary);background:var(--bg-hover)}.plugin-option.selected{border-color:var(--accent-primary);background:color-mix(in srgb,var(--accent-primary) 10%,var(--bg-card));box-shadow:0 0 0 2px color-mix(in srgb,var(--accent-primary) 30%,transparent)}.plugin-option .plugin-name{font-weight:600;margin-bottom:.25rem}.plugin-option .plugin-meta{display:flex;gap:.5rem;font-size:var(--font-size-sm);color:var(--text-muted);margin-bottom:.25rem}.plugin-option .plugin-extensions{color:var(--accent-cyan)}.plugin-option .plugin-types{color:var(--text-secondary)}.plugin-option .plugin-description{font-size:var(--font-size-sm);color:var(--text-secondary);line-height:1.4}.file-selector{display:flex;align-items:center;gap:1rem}.selected-file-name{color:var(--text-secondary);font-family:monospace;font-size:var(--font-size-sm)}.import-preview-container{min-height:100px}.import-preview-table-wrapper{max-height:300px;overflow:auto;border:1px solid var(--border-color);border-radius:var(--radius-sm)}.import-preview-table{font-size:var(--font-size-sm);margin:0}.import-preview-table th{position:sticky;top:0;background:var(--bg-secondary);z-index:1}.import-preview-table td{max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.import-summary{margin:0 0 .75rem 0;color:var(--text-primary)}.import-more{margin:.5rem 0 0 0;color:var(--text-muted);font-style:italic;font-size:var(--font-size-sm)}.import-empty,.import-error{padding:2rem;text-align:center;color:var(--text-muted)}.import-error{color:var(--accent-red)}.import-warnings{margin-top:1rem;padding:.75rem;background:color-mix(in srgb,var(--accent-yellow) 10%,var(--bg-card));border:1px solid var(--accent-yellow);border-radius:var(--radius-sm);font-size:var(--font-size-sm)}.import-warnings ul{margin:.5rem 0 0 1.25rem;padding:0}.import-warnings li{margin-bottom:.25rem}.plugin-list{display:flex;flex-direction:column;gap:.75rem}.plugin-item{display:flex;justify-content:space-between;align-items:center;padding:1rem;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md)}.plugin-item .plugin-info{flex:1}.plugin-item .plugin-name{font-weight:600}.plugin-item .plugin-version{color:var(--text-muted);font-size:var(--font-size-sm);margin-left:.5rem}.plugin-item .plugin-description{margin:.25rem 0;color:var(--text-secondary);font-size:var(--font-size-sm)}.plugin-item .plugin-extensions{font-size:var(--font-size-xs);color:var(--text-muted)}.plugin-item .plugin-actions{margin-left:1rem}.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(--bg-tertiary);border:2px solid var(--border-color);border-radius:var(--radius-xl);transition:background-color var(--transition-fast),border-color var(--transition-fast)}.toggle-slider:before{position:absolute;content:"";height:16px;width:16px;left:2px;bottom:2px;background-color:var(--text-muted);border-radius:var(--radius-full);transition:transform var(--transition-fast),background-color var(--transition-fast)}.toggle-switch input:checked+.toggle-slider{background-color:var(--accent-primary);border-color:var(--accent-primary)}.toggle-switch input:checked+.toggle-slider:before{transform:translateX(20px);background-color:var(--bg-card)}.toggle-switch input:focus+.toggle-slider{box-shadow:0 0 0 2px color-mix(in srgb,var(--accent-primary) 30%,transparent)}.ai-fill-wrapper{position:relative}.ai-fill-btn{position:absolute;right:.5rem;top:.5rem;font-size:.7rem;padding:.2rem .5rem;background:var(--accent-purple);color:var(--text-on-accent);border:none;border-radius:var(--radius-sm);cursor:pointer;font-family:var(--font-heading);font-weight:700;text-transform:uppercase;letter-spacing:.03em;transition:background var(--transition-fast),opacity var(--transition-fast);z-index:1}.ai-fill-btn:hover{background:color-mix(in srgb,var(--accent-purple) 80%,#000)}.ai-fill-btn:disabled{opacity:.6;cursor:wait}.milestones-section{margin-bottom:1.5rem}.milestones-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem;padding-bottom:.5rem;border-bottom:2px solid var(--border-color)}.milestones-header h3{margin:0;font-size:1rem;font-family:var(--font-heading);font-weight:700}.milestone-card{background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);padding:1rem;margin-bottom:.75rem;transition:background-color .1s;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.milestone-card:hover{background:var(--bg-secondary)}.milestone-card-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:.5rem}.milestone-card-header h4{margin:0;font-size:.95rem;font-family:var(--font-heading);font-weight:700}.milestone-card-header .milestone-status{font-size:.7rem;font-weight:700;text-transform:uppercase;padding:.15rem .4rem;border-radius:var(--radius-sm);background:var(--bg-secondary);color:var(--text-muted)}.milestone-card-header .milestone-status.completed{background:color-mix(in srgb,var(--accent-green) 15%,var(--bg-secondary));color:var(--accent-green)}.milestone-meta{display:flex;gap:1rem;font-size:.8rem;color:var(--text-muted);margin-bottom:.5rem}.milestone-progress{height:6px;background:var(--bg-secondary);border-radius:var(--radius-full);overflow:hidden;border:var(--border-width-sm) solid var(--border-color)}.milestone-progress-fill{height:100%;background:var(--accent-green);border-radius:var(--radius-full);transition:width var(--transition-fast)}.milestone-actions{display:flex;gap:.5rem;margin-top:.5rem}.milestone-actions button{font-size:.75rem;padding:.2rem .5rem;background:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm);cursor:pointer;color:var(--text-secondary);transition:background var(--transition-fast)}.milestone-actions button:hover{background:var(--bg-hover)}.milestone-actions button.danger:hover{background:color-mix(in srgb,var(--accent-red) 15%,var(--bg-secondary));color:var(--accent-red)}button.milestone-reorder-btn.btn{font-size:.65rem;padding:.15rem .35rem;line-height:1;min-width:1.5rem;text-align:center}.milestones-completed-section{margin-top:.75rem}.milestones-completed-toggle{font-size:.8rem;color:var(--text-secondary);padding:.25rem 0}.milestone-card-summary{padding:.5rem .75rem;opacity:.7}.milestone-card-summary .milestone-info{display:flex;align-items:center;gap:.5rem}.milestone-complete-badge{font-size:.7rem;font-weight:700;padding:.1rem .4rem;border-radius:var(--radius-sm);background:color-mix(in srgb,var(--accent-green) 15%,var(--bg-secondary));color:var(--accent-green)}.nav-dot{display:none;position:fixed;bottom:calc(20px + env(safe-area-inset-bottom,0px));right:20px;width:70px;height:70px;border-radius:var(--radius-full);background:var(--bg-card);color:var(--text-primary);border:var(--border-width) solid var(--border-color);z-index:1100;align-items:center;justify-content:center;cursor:pointer;user-select:none;touch-action:none;font-family:var(--font-display);font-size:1rem;font-weight:700;letter-spacing:.05em;transition:background-color .15s ease}.nav-dot:active{background-color:var(--bg-tertiary)}.nav-dot.dial-open{background-color:var(--accent-blue);color:var(--text-on-accent)}.nav-dot-icon{pointer-events:none}.nav-dot-status{display:none;position:fixed;bottom:calc(8px + env(safe-area-inset-bottom,0px));right:20px;width:70px;z-index:1100;justify-content:center;gap:4px;pointer-events:none}.nav-dot-status .tab-status-dot{width:10px;height:10px;border-radius:50%;display:inline-block;border:none}.nav-dial{display:none;position:fixed;z-index:1099;pointer-events:none}.nav-dial.visible{display:block;pointer-events:auto}.nav-dial.hidden{display:none}.nav-dial-backdrop{display:none;position:fixed;inset:0;background:rgba(0,0,0,.3);z-index:1098}.nav-dial-backdrop.visible{display:block}.nav-dial-item{position:absolute;width:72px;height:28px;border-radius:var(--radius-sm);background:var(--bg-card);border:var(--border-width) solid var(--border-color);display:flex;align-items:center;justify-content:center;font-size:.6rem;font-weight:700;color:var(--text-primary);cursor:pointer;opacity:0;transform-origin:center center;transition:opacity .2s ease,background .15s ease,filter .15s ease}.nav-dial.visible .nav-dial-item{opacity:1}.nav-dial-item:hover{filter:brightness(1.05)}.nav-dial-item:active{filter:brightness(.95)}.nav-dial-item.active{background-color:var(--accent-blue);color:var(--text-on-accent);border-color:var(--border-color)}.nav-dial-item.nav-dial-subitem{font-size:.55rem;background:var(--bg-secondary)}.nav-dial-item.nav-dial-subitem.active{background-color:var(--accent-blue);color:var(--text-on-accent)}.nav-dial-item.nav-dial-center{width:44px;height:44px;border-radius:var(--radius-full);font-size:1.25rem;background-color:var(--accent-green);color:var(--text-on-accent);border-color:var(--border-color)}.nav-dial-label{pointer-events:none;font-family:var(--font-sans);text-transform:uppercase;letter-spacing:.05em;line-height:1;text-align:center;white-space:nowrap}.action-sheet{position:fixed;inset:0;z-index:10001;display:flex;flex-direction:column;justify-content:flex-end}.action-sheet.hidden{display:none}.action-sheet-backdrop{position:absolute;inset:0;background:rgba(0,0,0,.4)}.action-sheet-container{position:relative;background:var(--bg-card);border-top:var(--border-width) solid var(--border-color);border-radius:var(--radius-lg) var(--radius-lg) 0 0;padding:.5rem 1rem calc(.5rem + env(safe-area-inset-bottom,0px));max-height:60vh;overflow-y:auto;animation:sheetSlideUp .25s ease-out}.action-sheet-handle{width:36px;height:4px;border-radius:2px;background:var(--text-muted);margin:0 auto .75rem;opacity:.4}.action-sheet-content button{display:flex;align-items:center;gap:.75rem;width:100%;padding:.875rem .5rem;background:0 0;border:none;border-bottom:1px solid var(--bg-secondary);font-size:var(--font-size-base);font-weight:600;color:var(--text-primary);text-align:left;cursor:pointer}.action-sheet-content button:last-child{border-bottom:none}.action-sheet-content button:active{background:var(--bg-secondary)}.action-sheet-content button.danger{color:var(--accent-red)}.action-sheet-cancel{display:block;width:100%;padding:.875rem;margin-top:.5rem;background:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-md);font-size:var(--font-size-base);font-weight:700;color:var(--text-primary);text-align:center;cursor:pointer}.action-sheet-cancel:active{background:var(--bg-tertiary)}.modal-drag-handle{display:none;width:36px;height:4px;border-radius:2px;background:var(--text-muted);margin:.5rem auto 0;opacity:.4}.mobile-sort-bar{display:none;gap:.5rem;padding:.5rem 0;align-items:center}.mobile-sort-bar select{flex:1;font-size:var(--font-size-sm)}.mobile-filter-toggle{display:none}.swipe-actions-container{position:relative;overflow:hidden}.swipe-actions-bg{position:absolute;top:0;bottom:0;display:flex;align-items:center;padding:0 1rem;font-weight:700;font-size:var(--font-size-sm);color:var(--text-on-accent)}.swipe-actions-bg.swipe-left{right:0;background:var(--accent-green)}.swipe-actions-bg.swipe-right{left:0;background:var(--accent-red)}.swipe-content{position:relative;background:var(--bg-card);transition:transform .15s ease}.pull-to-refresh-indicator{display:none;text-align:center;padding:.75rem;font-size:var(--font-size-sm);color:var(--text-muted);font-weight:600}.pull-to-refresh-indicator.visible{display:block}.event-date-group-header{display:none}.day-plan-sidebar-toggle{display:none}@keyframes sheetSlideUp{from{transform:translateY(100%)}to{transform:translateY(0)}}@keyframes sheetSlideDown{from{transform:translateY(0)}to{transform:translateY(100%)}}@keyframes dialFadeIn{from{opacity:0}to{opacity:1}}@media (max-width:768px){body{padding-bottom:env(safe-area-inset-bottom,0)}.tab-navigation{display:none!important}.app-header{padding:calc(.5rem + env(safe-area-inset-top)) 1rem .5rem 1rem}.app-header .header-actions{display:flex;flex-direction:column;gap:.25rem}.app-header .header-actions .settings-btn{font-size:.75rem;padding:.3rem .6rem}.app-subtitle{display:none}.pill-nav{overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;padding:var(--space-1) var(--space-3)}.tab-group>.subview>.page-header{position:static}.pill-nav::-webkit-scrollbar{display:none}.mobile-view-title{display:inline;font-size:.875rem;color:var(--text-muted);font-weight:500;line-height:1}.nav-dot{display:flex}.nav-dot-status{display:flex}.nav-dot-status.dial-open{display:none}.main-content{padding:.75rem}.page-header{flex-wrap:wrap;gap:.5rem}.page-header .btn-primary{display:none}.page-title{display:none}.modal-overlay{align-items:flex-end}.modal-container{width:100%!important;max-width:100%!important;max-height:90vh;border-radius:var(--radius-lg) var(--radius-lg) 0 0;margin:0;border-bottom:none;padding-bottom:env(safe-area-inset-bottom,0)}.modal-container.modal-large{max-width:100%!important;width:100%!important;max-height:95vh;border-radius:var(--radius-lg) var(--radius-lg) 0 0}.modal-drag-handle{display:block}.modal-header{padding:.75rem 1rem}.modal-content{padding:1rem}@keyframes modalSlideIn{from{transform:translateY(100%)}to{transform:translateY(0)}}@keyframes modalSlideOut{from{transform:translateY(0)}to{transform:translateY(100%)}}.toast,.toast-undo{bottom:calc(env(safe-area-inset-bottom,0px) + 5rem)!important;left:1rem!important;right:1rem!important;max-width:none!important}.task-table{border:none;box-shadow:none;background:0 0}.task-header-row{display:none!important}.task-row{display:flex!important;flex-direction:column;gap:.25rem;padding:.75rem 1rem;margin-bottom:.5rem;background:var(--bg-card);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-md);border-left:4px solid var(--text-muted)}.task-row.task-pending{border-left-color:var(--text-muted)}.task-row .task-cell.priority-h~.task-cell:first-child,.task-row:has(.priority-h){border-left-color:var(--accent-red)}.task-row:has(.priority-m){border-left-color:var(--accent-yellow)}.task-row:has(.priority-l){border-left-color:var(--text-muted)}.task-row .task-cell{display:flex!important;overflow:visible;padding:0}.task-cell.task-description{font-weight:600;font-size:var(--font-size-base)}.task-cell.task-due,.task-cell.task-project{font-size:var(--font-size-sm);color:var(--text-secondary)}.task-row .task-cell.task-project::before{content:none}.task-cell.task-progress,.task-cell.task-recurrence,.task-row .task-cell:nth-child(3){display:none!important}.task-cell.task-project{order:2}.task-cell.task-due{order:3}.task-cell.task-description{order:1}.task-cell.task-actions-cell{order:4;justify-content:flex-end}.task-cell.task-progress:has(.progress-bar-container){display:flex!important;order:5}.task-actions-cell .bulk-checkbox{display:none}.mobile-sort-bar{display:flex}.mobile-filter-toggle{display:inline-flex;align-items:center;gap:.25rem;padding:.5rem .75rem;background:var(--bg-card);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm);font-size:var(--font-size-sm);font-weight:600;cursor:pointer}.filter-bar{display:none!important}.filter-bar.mobile-visible{display:flex!important;flex-direction:column;position:fixed;bottom:0;left:0;right:0;background:var(--bg-card);border-top:var(--border-width) solid var(--border-color);border-radius:var(--radius-lg) var(--radius-lg) 0 0;padding:1rem;padding-bottom:calc(1rem + env(safe-area-inset-bottom,0px));z-index:1050;box-shadow:0 -4px 12px rgba(0,0,0,.1)}.event-header-row{display:none!important}.event-row-virtual{display:flex!important;flex-direction:column;gap:.125rem;padding:.75rem 1rem;border-bottom:1px solid var(--bg-secondary)}.event-cell-date{font-weight:700;font-size:var(--font-size-sm);color:var(--text-secondary)}.event-cell-time{font-size:var(--font-size-sm);color:var(--text-muted)}.event-cell-title{font-weight:600;font-size:var(--font-size-base)}.event-cell-location{font-size:var(--font-size-sm);color:var(--text-secondary)}.event-date-group-header{display:flex;position:sticky;top:0;z-index:5;padding:.5rem 1rem;background:var(--bg-secondary);font-weight:700;font-size:var(--font-size-sm);text-transform:uppercase;letter-spacing:.05em;color:var(--text-primary);border-bottom:var(--border-width-sm) solid var(--border-color)}.email-item{padding:.625rem .75rem}.email-from{font-size:var(--font-size-sm)}.email-subject{font-size:var(--font-size-base)}.email-preview{display:none}.email-date{font-size:var(--font-size-xs)}.email-item .bulk-checkbox{display:none}.day-plan-content{flex-direction:column}.day-plan-sidebar{width:100%;max-height:none;border-top:var(--border-width-sm) solid var(--border-color);order:2}.day-plan-sidebar.collapsed .sidebar-task-list{display:none}.day-plan-sidebar-toggle{display:flex;align-items:center;justify-content:space-between;width:100%;padding:.625rem .75rem;background:var(--bg-secondary);border:none;border-bottom:1px solid var(--border-color);font-size:var(--font-size-sm);font-weight:700;cursor:pointer;color:var(--text-primary)}.day-plan-main{order:1}.day-plan-nav{flex-wrap:wrap;gap:.25rem}.weekly-review-content{padding:0}.monthly-review-content{padding:0}.month-reflection-textarea,.prompt-input{resize:none;overflow:hidden}.monthly-review-nav{flex-wrap:wrap;gap:.25rem}.monthly-review-month-display{font-size:1rem}.day-summary-sheet{padding:.5rem 0}.day-summary-date{font-size:1rem;font-weight:700;margin-bottom:.75rem;color:var(--text-primary)}.day-summary-stats{display:flex;gap:.5rem;margin-bottom:1rem}.day-summary-chip{padding:.25rem .75rem;background:var(--bg-secondary);border-radius:var(--radius-sm);font-size:var(--font-size-sm);font-weight:600;color:var(--text-secondary)}.day-summary-list{list-style:none;padding:0;margin:0 0 1rem 0}.day-summary-item{padding:.5rem 0;border-bottom:1px solid var(--bg-secondary);font-size:var(--font-size-sm);color:var(--text-primary)}.day-summary-time{font-weight:600;color:var(--text-secondary);margin-right:.5rem}.day-summary-more{color:var(--text-muted);font-style:italic}.day-summary-empty{color:var(--text-muted);font-size:var(--font-size-sm);margin:.5rem 0 1rem}.day-summary-go-btn{width:100%;margin-top:.5rem}.bulk-actions-bar{position:fixed;bottom:0;left:0;right:0;z-index:1050;border-radius:var(--radius-lg) var(--radius-lg) 0 0;padding-bottom:calc(.75rem + env(safe-area-inset-bottom,0px));box-shadow:0 -4px 12px rgba(0,0,0,.15)}.pagination-controls{padding:.5rem}.pagination-controls .btn{padding:.5rem .75rem;font-size:var(--font-size-sm)}}@media (hover:none){.task-row:hover{background-color:transparent}.task-row-clickable:hover{background:0 0}.event-row-virtual:hover{background-color:transparent}.email-item:hover{background-color:transparent}.card:hover{background-color:var(--bg-card);transform:none;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.btn:hover{background:var(--bg-card)}.btn-primary:hover{background-color:var(--accent-blue)}.btn-danger:hover{background-color:var(--accent-red)}.dashboard-item:hover{background:var(--bg-card);transform:none;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.kanban-card:hover{background:var(--bg-card);transform:none;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.saved-view-item:hover{background:var(--bg-card);color:var(--text-primary);transform:none;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.context-menu-item:hover{background:0 0;color:var(--text-primary)}.modal-close:hover{background:var(--bg-card);color:var(--text-primary)}.month-heatmap-cell:hover{background:0 0;transform:none}}.view-toggle{display:flex;gap:0;margin-left:auto}.view-toggle-btn{padding:.35rem .75rem;border:var(--border-width-sm) solid var(--border-color);background:var(--bg-secondary);font-family:var(--font-body);font-size:var(--font-size-md);cursor:pointer;transition:background var(--transition-fast),box-shadow var(--transition-fast)}.view-toggle-btn.active{background:var(--bg-card);font-weight:600}.view-toggle-btn:first-child{border-radius:var(--radius-xs) 0 0 var(--radius-xs)}.view-toggle-btn:last-child{border-radius:0 var(--radius-xs) var(--radius-xs) 0;border-left:none}.kanban-board{display:grid;grid-template-columns:repeat(3,1fr);gap:1rem;padding:.5rem 0;min-height:400px}.kanban-column{background:var(--bg-card);border:var(--border-width) solid var(--border-color);display:flex;flex-direction:column;min-height:300px;max-height:calc(100vh - 200px)}.kanban-column-header{padding:.75rem 1rem;border-bottom:2px solid var(--border-color);font-family:var(--font-heading);font-weight:700;display:flex;justify-content:space-between;align-items:center}.kanban-column-count{font-family:var(--font-body);font-size:var(--font-size-sm);color:var(--text-secondary)}.kanban-column-body{flex:1;overflow-y:auto;padding:.5rem;display:flex;flex-direction:column;gap:.5rem}.kanban-column.drag-over{background-color:var(--bg-tertiary)}.kanban-empty{text-align:center;padding:2rem 1rem;color:var(--text-secondary);font-size:var(--font-size-sm)}.kanban-card{padding:.75rem;background:var(--bg-card);border:var(--border-width-sm) solid var(--border-color);cursor:grab;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color);transition:transform .15s ease,box-shadow .15s ease,background-color .15s ease;border-left:4px solid transparent}.kanban-card:hover{background:var(--bg-secondary);transform:translate(-2px,-2px);box-shadow:calc(var(--shadow-offset) + 2px) calc(var(--shadow-offset) + 2px) 0 var(--border-color)}.kanban-card.dragging{opacity:.5;cursor:grabbing}.kanban-card.priority-high{border-left-color:var(--accent-red)}.kanban-card.priority-medium{border-left-color:var(--accent-yellow)}.kanban-card.priority-low{border-left-color:var(--accent-green)}.kanban-card-title{font-weight:600;margin-bottom:.25rem}.kanban-card-meta{font-size:var(--font-size-sm);color:var(--text-secondary);display:flex;gap:.5rem;flex-wrap:wrap}.kanban-card-due.overdue{color:var(--accent-red);font-weight:600}.progress-bar-mini{height:3px;background:var(--bg-tertiary);border-radius:2px;margin-top:.5rem}.progress-bar-mini .progress-fill{height:100%;background:var(--accent-green);border-radius:2px}@media (max-width:768px){.kanban-board{grid-template-columns:1fr}.kanban-column{max-height:none}} | |
| 1 | > | \ No newline at end of file | |
| 1 | + | @font-face{font-family:Reglo;src:url('../fonts/Reglo-Bold.woff2') format('woff2');font-weight:700;font-style:normal;font-display:swap}*,::after,::before{box-sizing:border-box;margin:0;padding:0}:root{--bg-primary:#E0E4FA;--bg-secondary:#CDD3F0;--bg-tertiary:#BAC2E6;--bg-card:#FFFFFF;--text-primary:#000000;--text-secondary:#2D2D2D;--text-muted:#6B6B6B;--accent-yellow:#F7D154;--accent-green:#5CB85C;--accent-blue:#6196FF;--accent-purple:#7B68EE;--accent-red:#DC3545;--accent-cyan:#17A2B8;--border-color:#000000;--border-width:2px;--border-width-sm:2px;--accent-color:var(--accent-blue);--accent-primary:var(--accent-blue);--bg-hover:var(--bg-tertiary);--border-light:var(--bg-tertiary);--text-on-accent:var(--bg-card);--shadow-offset-xs:1px;--shadow-offset-md:3px;--shadow-offset:4px;--shadow-offset-lg:6px;--shadow-offset-xl:8px;--shadow-brutal-xs:var(--shadow-offset-xs) var(--shadow-offset-xs) 0 var(--border-color);--shadow-brutal-md:var(--shadow-offset-md) var(--shadow-offset-md) 0 var(--border-color);--shadow-brutal-lg:var(--shadow-offset-lg) var(--shadow-offset-lg) 0 var(--border-color);--shadow-brutal-xl:var(--shadow-offset-xl) var(--shadow-offset-xl) 0 var(--border-color);--radius-xs:3px;--radius-sm:5px;--radius-md:5px;--radius-lg:10px;--radius-xl:20px;--radius-full:50%;--width-container:1400px;--width-modal:560px;--width-sidebar:280px;--space-1:0.25rem;--space-2:0.5rem;--space-3:0.75rem;--space-4:1rem;--space-5:1.25rem;--space-6:1.5rem;--font-sans:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;--font-serif:Georgia,'Times New Roman',serif;--font-mono:'SF Mono','Consolas','Liberation Mono',monospace;--font-display:'Reglo',var(--font-serif);--font-heading:var(--font-sans);--font-body:var(--font-sans);--font-size-xxs:0.65rem;--font-size-xs:0.7rem;--font-size-sm:0.75rem;--font-size-md:0.8rem;--font-size-base:0.875rem;--font-size-lg:1rem;--font-size-xl:1.1rem;--font-size-2xl:1.25rem;--font-size-3xl:1.5rem;--font-size-4xl:1.75rem;--line-height-tight:1.25;--line-height-normal:1.5;--line-height-relaxed:1.75;--transition-fast:0.1s;--transition-normal:0.15s;--transition-slow:0.3s;--overlay-color:color-mix(in srgb, var(--text-primary) 60%, transparent)}html{font-size:16px}.flex-1{flex:1}.flex-center-gap{display:flex;align-items:center;gap:.5rem}.text-sm-secondary{font-size:.875rem;color:var(--text-secondary)}.text-xs-secondary{font-size:.75rem;color:var(--text-secondary)}.text-accent-red{color:var(--accent-red)}.mb-1{margin-bottom:1rem}.settings-divider{margin-top:1.5rem;padding-top:1.5rem;border-top:2px solid var(--border-color)}.settings-heading{margin-bottom:1rem;font-family:var(--font-heading)}.settings-desc{font-size:.875rem;color:var(--text-secondary);margin-bottom:1rem}.subtask-item{display:flex;align-items:center;gap:.5rem;padding:.5rem;background:var(--bg-secondary);border-radius:4px;margin-bottom:.5rem}.subtask-item-linked{display:flex;align-items:center;gap:.5rem;padding:.5rem;background:var(--bg-tertiary);border-radius:4px;margin-bottom:.5rem;border-left:var(--border-width) solid var(--accent-color)}.subtask-checkbox{cursor:pointer;width:18px;height:18px}.subtask-checkbox-disabled{cursor:not-allowed;width:18px;height:18px;opacity:.5}.subtask-text-done{text-decoration:line-through;opacity:.6}body{font-family:var(--font-sans);background-color:var(--bg-primary);color:var(--text-primary);line-height:1.6;height:100vh;overflow:hidden;display:flex;flex-direction:column}.app-header{background:var(--bg-card);border-bottom:var(--border-width) solid var(--border-color);padding:.75rem 1.5rem;display:flex;justify-content:space-between;align-items:center}.header-content{display:flex;align-items:center;gap:.75rem}.header-actions{display:flex;align-items:center;gap:.5rem}.app-title{font-family:var(--font-display);font-size:1.75rem;font-weight:700;color:var(--text-primary);letter-spacing:-.02em}.app-subtitle{font-size:.875rem;color:var(--text-muted);font-weight:500;line-height:1}.mobile-view-title{display:none}.tab-navigation{display:flex;justify-content:center;gap:.5rem}.tab{display:flex;align-items:center;gap:.5rem;padding:.75rem 1.25rem;text-decoration:none;color:var(--text-primary);background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);font-weight:600;transition:background-color .15s ease}.tab:hover{background:var(--bg-secondary)}.tab.active{background-color:var(--accent-blue);color:var(--text-on-accent)}.tab-icon{font-size:1.1rem}.tab-label{font-weight:600;font-size:.9rem}.tab.tab-right{margin-left:auto}.tab-group .subview.hidden{display:none}.pill-nav{display:flex;align-items:center;gap:var(--space-1);padding:0;margin-bottom:1rem;min-height:2rem}.pill{padding:var(--space-1) var(--space-3);border-radius:var(--radius-xl);border:var(--border-width-sm) solid var(--border-color);background:var(--bg-card);font-family:var(--font-sans);font-size:var(--font-size-sm);font-weight:600;cursor:pointer;transition:background-color var(--transition-fast)}.pill:hover{background:var(--bg-tertiary)}.pill.active{background:var(--text-primary);color:var(--bg-card);border-color:var(--text-primary)}.main-content{flex:1;max-width:var(--width-container);width:100%;margin:0 auto;padding:1.5rem 1.75rem 2rem}.page-header{display:flex;justify-content:space-between;align-items:center;gap:.5rem;margin-bottom:1rem}.page-title{font-family:var(--font-heading);font-size:1.75rem;font-weight:700;color:var(--text-primary)}.tab-group{position:relative}.tab-group>.subview>.page-header{position:absolute;top:0;right:0;margin:0;z-index:1}.tab-group .page-header .page-title{display:none}#day-plan-view>.page-header,#project-dashboard-view>.page-header{position:static;margin-bottom:1rem}#project-dashboard-view .page-title{display:block}.btn{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;padding:.625rem 1.25rem;border:var(--border-width) solid var(--border-color);border-radius:var(--radius-sm);font-size:.9rem;font-weight:600;cursor:pointer;transition:background-color .15s ease;text-decoration:none;background:var(--bg-card);color:var(--text-primary)}.btn:hover{background:var(--bg-secondary)}.btn:active{background:var(--bg-tertiary)}.btn:disabled{background:var(--bg-tertiary);color:var(--text-muted);cursor:not-allowed;opacity:.7}.btn:disabled:hover{background:var(--bg-tertiary)}.btn-primary{background-color:var(--accent-blue);color:var(--text-on-accent)}.btn-primary:hover{background-color:color-mix(in srgb,var(--accent-blue) 85%,#000)}.btn-primary:active{background-color:color-mix(in srgb,var(--accent-blue) 70%,#000)}.btn-secondary{background-color:var(--bg-secondary);color:var(--text-primary)}.btn-danger{background-color:var(--accent-red);color:var(--text-on-accent)}.btn-danger:hover{background-color:color-mix(in srgb,var(--accent-red) 85%,#000)}.btn-danger:active{background-color:color-mix(in srgb,var(--accent-red) 70%,#000)}.btn-sm{padding:.375rem .75rem;font-size:.8rem}.quick-add{display:flex;gap:.75rem;margin-bottom:1.5rem}.quick-add-input{flex:1;padding:.875rem 1rem;border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);background-color:var(--bg-card);font-size:1rem;color:var(--text-primary)}.quick-add-input::placeholder{color:var(--text-muted)}.quick-add-input:focus{outline:0;background-color:var(--accent-blue);color:var(--text-on-accent);box-shadow:0 0 0 2px var(--border-color)}.cards-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:1.25rem}.card{background-color:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);padding:1.25rem;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color);transition:transform .15s ease,box-shadow .15s ease,background-color .15s ease;cursor:pointer}.card:hover{background-color:var(--bg-secondary);transform:translate(-2px,-2px);box-shadow:calc(var(--shadow-offset) + 2px) calc(var(--shadow-offset) + 2px) 0 var(--border-color)}.card-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:.75rem}.card-title{font-family:var(--font-heading);font-size:1.1rem;font-weight:700;color:var(--text-primary)}.card-description{font-size:.9rem;color:var(--text-secondary);margin-bottom:1rem}.markdown-content{font-size:.9rem;color:var(--text-secondary);line-height:1.5}.markdown-content p{margin:0 0 .5em 0}.markdown-content p:last-child{margin-bottom:0}.markdown-content ol,.markdown-content ul{margin:0 0 .5em 1.5em;padding:0}.markdown-content code{background:var(--bg-tertiary);padding:.1em .3em;border-radius:3px;font-size:.85em}.markdown-content pre{background:var(--bg-tertiary);padding:.5em;border-radius:4px;overflow-x:auto;margin:0 0 .5em 0}.markdown-content pre code{background:0 0;padding:0}.markdown-content a{color:var(--accent-color)}.markdown-content blockquote{border-left:3px solid var(--border-color);margin:0 0 .5em 0;padding-left:.75em;color:var(--text-secondary)}.markdown-content h1,.markdown-content h2,.markdown-content h3{margin:.5em 0 .25em 0;font-size:1em;font-weight:600;color:var(--text-primary)}.markdown-content table{border-collapse:collapse;margin:.5em 0}.markdown-content td,.markdown-content th{border:1px solid var(--border-color);padding:.25em .5em}.markdown-content img{max-width:100%}.card-meta{display:flex;gap:.5rem;flex-wrap:wrap}.badge,.tag{display:inline-flex;align-items:center;padding:.25rem .625rem;border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm);font-size:.8125rem;font-weight:600;background:var(--bg-card);color:var(--text-primary)}.badge[data-color=green],.tag[data-color=green]{background-color:color-mix(in srgb,var(--accent-green) 20%,var(--bg-card));border-color:var(--accent-green)}.badge[data-color=yellow],.tag[data-color=yellow]{background-color:color-mix(in srgb,var(--accent-yellow) 20%,var(--bg-card));border-color:var(--accent-yellow)}.badge[data-color=red],.tag[data-color=red]{background-color:color-mix(in srgb,var(--accent-red) 20%,var(--bg-card));border-color:var(--accent-red)}.badge[data-color=cyan],.tag[data-color=cyan]{background-color:color-mix(in srgb,var(--accent-cyan) 20%,var(--bg-card));border-color:var(--accent-cyan)}.badge[data-color=purple],.tag[data-color=purple]{background-color:color-mix(in srgb,var(--accent-purple) 20%,var(--bg-card));border-color:var(--accent-purple)}.badge[data-color=muted],.tag[data-color=muted]{background-color:var(--bg-tertiary);border-color:var(--text-muted)}.tag.status-active{background-color:color-mix(in srgb,var(--accent-green) 20%,var(--bg-card));border-color:var(--accent-green)}.tag.status-on_hold,.tag.status-onhold{background-color:color-mix(in srgb,var(--accent-yellow) 20%,var(--bg-card));border-color:var(--accent-yellow)}.tag.status-archived{background-color:var(--bg-tertiary);border-color:var(--text-muted)}.tag.status-inactive{background-color:color-mix(in srgb,var(--accent-red) 20%,var(--bg-card));border-color:var(--accent-red)}.tag.status-completed{background-color:color-mix(in srgb,var(--accent-cyan) 20%,var(--bg-card));border-color:var(--accent-cyan)}.data-table{width:100%;border-collapse:separate;border-spacing:0;background-color:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);overflow:hidden;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.data-table td,.data-table th{padding:1rem 1.25rem;text-align:left;border-bottom:2px solid var(--border-color)}.data-table th{background-color:var(--bg-secondary);font-size:.8rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--text-primary)}.data-table tbody tr{transition:background-color .15s ease}.data-table tbody tr:hover{background-color:var(--bg-secondary)}.data-table tbody tr:last-child td{border-bottom:none}.data-table tbody tr.keyboard-selected,.data-table tbody tr.selected{background-color:color-mix(in srgb,var(--accent-blue) 25%,var(--bg-card))}.task-table{width:100%;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-lg);overflow:hidden;display:flex;flex-direction:column;flex:1;min-height:0;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.task-header-row,.task-row{display:grid;grid-template-columns:1fr 140px 60px 110px 90px 100px 90px;align-items:center;gap:.75rem}.task-header-row{background-color:var(--bg-secondary);border-bottom:2px solid var(--border-color);padding:0 1.25rem}.task-header-row .task-cell{padding:.75rem 0;font-size:.8rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--text-primary)}.task-list-container{flex:1;min-height:0;overflow-y:auto;position:relative}.task-row{padding:.75rem 1.25rem;border-bottom:1px solid var(--border-color);transition:background-color .15s ease;cursor:pointer}.task-row:hover{background-color:var(--bg-secondary)}.task-row:last-child{border-bottom:none}.task-row.keyboard-selected,.task-row.selected{background-color:color-mix(in srgb,var(--accent-blue) 25%,var(--bg-card))}.task-cell{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.task-actions-header{text-align:right}.virtual-scroller-empty{padding:2rem;text-align:center;color:var(--text-secondary)}.event-table tbody tr{cursor:pointer}.task-description{font-weight:600;white-space:normal;display:flex;flex-wrap:wrap;align-items:center;gap:.25rem .5rem}.task-description-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}.task-project{font-size:.85rem;color:var(--text-secondary);white-space:nowrap}.priority-high,.priority-low,.priority-medium{display:inline-block;padding:.25rem .5rem;border-radius:var(--radius-xs);font-weight:700;text-align:center}.priority-high{color:var(--accent-red);background:#fde8ea;background:color-mix(in srgb,var(--accent-red) 15%,var(--bg-card))}.priority-medium{color:var(--accent-yellow);background:#fef8e6;background:color-mix(in srgb,var(--accent-yellow) 15%,var(--bg-card))}.priority-low{color:var(--text-muted);background:var(--bg-secondary)}.sortable{cursor:pointer;user-select:none;white-space:nowrap}.sortable:hover{background:var(--bg-hover)}.sort-arrow{display:inline-block;width:.8em;margin-left:.25rem;opacity:.3}.sort-arrow::after{content:'\2195'}.sortable.sort-asc .sort-arrow::after{content:'\2191'}.sortable.sort-desc .sort-arrow::after{content:'\2193'}.sortable.sort-asc .sort-arrow,.sortable.sort-desc .sort-arrow{opacity:1}.task-overdue .task-description-text{color:var(--accent-red)}.task-overdue .task-due{color:var(--accent-red);font-weight:600}.task-tags{display:flex;gap:.25rem;flex-wrap:wrap}.task-tag{background-color:var(--bg-tertiary);color:var(--text-primary);padding:.125rem .5rem;border-radius:var(--radius-xs);font-size:.75rem;font-weight:600;border:1px solid var(--border-color)}.recurrence-icon{color:var(--accent-purple);font-size:.85rem;font-weight:700}.annotation-badge{background-color:var(--accent-yellow);color:var(--text-primary);padding:.125rem .5rem;border-radius:var(--radius-xs);font-size:.7rem;font-weight:700;border:var(--border-width-sm) solid var(--border-color)}.subtask-badge{background-color:var(--bg-secondary);color:var(--text-primary);padding:.125rem .5rem;border-radius:var(--radius-xs);font-size:.7rem;font-weight:700;border:var(--border-width-sm) solid var(--border-color);margin-left:.25rem}.task-started{border-left:4px solid var(--accent-green)}.task-completed{opacity:.5;text-decoration:line-through}.task-deleted{display:none}.due-overdue{color:var(--accent-red);font-weight:700;background:#fde8ea;background:color-mix(in srgb,var(--accent-red) 15%,var(--bg-card));padding:.25rem .5rem;border-radius:var(--radius-xs)}.due-today{color:var(--accent-yellow);font-weight:700;background:#fef8e6;background:color-mix(in srgb,var(--accent-yellow) 15%,var(--bg-card));padding:.25rem .5rem;border-radius:var(--radius-xs)}.due-soon{color:var(--text-secondary)}.due-future{color:var(--text-muted)}.events-list{display:flex;flex-direction:column;flex:1;min-height:0;gap:1rem}.event-table-virtual{width:100%;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-lg);overflow:hidden;display:flex;flex-direction:column;flex:1;min-height:0;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.event-header-row,.event-row-virtual{display:grid;grid-template-columns:100px 80px 1fr 150px;align-items:center;gap:.5rem}.event-header-row{background-color:var(--bg-secondary);border-bottom:2px solid var(--border-color);flex-shrink:0}.event-header-row .event-cell{padding:1rem 1.25rem;font-size:.8rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--text-primary)}.event-list-container{flex:1;min-height:0;overflow-y:auto;position:relative}.event-row-virtual{padding:.75rem 1.25rem;border-bottom:1px solid var(--border-color);transition:background-color .15s ease;cursor:pointer}.event-row-virtual:hover{background-color:var(--bg-secondary)}.event-row-virtual:last-child{border-bottom:none}.event-row-virtual.event-past{opacity:.7}.event-cell{overflow:hidden;text-overflow:ellipsis}.event-row{cursor:pointer}.event-cell-date{white-space:nowrap}.event-cell-date .event-date-num{font-weight:700;font-size:.9rem;color:var(--text-primary);margin-right:.5rem}.event-date-badge{display:inline-block;padding:.15rem .4rem;background:var(--accent-green);color:var(--text-on-accent);font-size:.7rem;font-weight:700;text-transform:uppercase;border-radius:var(--radius-xs);margin-right:.5rem}.event-cell-time{font-family:var(--font-mono);font-size:.85rem;color:var(--text-secondary)}.event-cell-title{font-weight:600}.event-cell-location{color:var(--text-secondary);font-size:.875rem}.event-date-badge.event-proximity-today{background:var(--accent-green)}.event-date-badge.event-proximity-tomorrow{background:var(--accent-yellow);color:var(--text-primary)}.event-date-badge.event-proximity-week{background:var(--accent-cyan)}.event-date-badge.event-proximity-future{background:var(--accent-blue)}.event-date-badge.event-proximity-past{background:var(--text-muted)}.event-row.event-past{opacity:.7}.no-upcoming-events{text-align:center;padding:2rem;color:var(--text-secondary);font-style:italic}.past-events-section{margin-top:.5rem}.past-events-toggle{display:flex;align-items:center;gap:.75rem;padding:.75rem 1rem;background:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm);cursor:pointer;font-weight:600;color:var(--text-secondary);transition:background-color .15s ease,color .15s ease;list-style:none}.past-events-toggle::-webkit-details-marker{display:none}.past-events-toggle::before{content:'▶';font-size:.7rem;transition:transform .15s ease}.past-events-section[open] .past-events-toggle::before{transform:rotate(90deg)}.past-events-toggle:hover{background:var(--bg-tertiary);color:var(--text-primary)}.past-events-label{flex:1}.past-events-count{background:var(--text-muted);color:var(--text-on-accent);font-size:.75rem;padding:.15rem .5rem;border-radius:var(--radius-sm)}.past-events-section .event-table-past{margin-top:.75rem;opacity:.85}.past-events-section .event-list-container{max-height:300px}.event-item{display:flex;gap:1rem;padding:1rem;background-color:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);transition:background-color .15s ease;cursor:pointer}.event-item:hover{background-color:var(--bg-secondary)}.event-date{flex-shrink:0;width:80px;text-align:center;padding:.75rem;background-color:var(--accent-green);border-radius:var(--radius-sm);color:var(--text-on-accent)}.event-date-day{font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em}.event-date-num{font-size:1.5rem;font-weight:700}.event-content{flex:1}.event-title{font-family:var(--font-heading);font-weight:700;font-size:1.1rem;color:var(--text-primary);margin-bottom:.25rem}.event-details{font-size:.875rem;color:var(--text-secondary);display:flex;gap:1rem}.event-location,.event-time{display:flex;align-items:center;gap:.25rem}.event-project{margin-top:.5rem}.email-list{display:flex;flex-direction:column;background-color:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);overflow:hidden;flex:1;min-height:0;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.email-list-container{flex:1;min-height:0;overflow-y:auto;position:relative}.email-item{display:flex;gap:1rem;padding:1rem;border-bottom:2px solid var(--border-color);transition:background-color .15s ease;cursor:pointer}.email-item:last-child{border-bottom:none}.email-item:hover{background-color:var(--bg-secondary)}.email-item.unread{background-color:color-mix(in srgb,var(--accent-blue) 20%,var(--bg-card));border-left:4px solid var(--accent-blue)}.email-item.unread .email-subject{font-weight:700}.email-item.unread .email-from{font-weight:700}.email-item.outgoing{border-left:4px solid var(--accent-green)}.email-checkbox{flex-shrink:0;margin-top:.25rem}.email-content{flex:1;min-width:0}.email-header{display:flex;justify-content:space-between;margin-bottom:.25rem;align-items:center;gap:.5rem}.thread-badge{background-color:var(--bg-tertiary);color:var(--text-secondary);font-size:.7rem;font-weight:600;padding:.1rem .4rem;border-radius:var(--radius-md);min-width:1.25rem;text-align:center}.email-from{color:var(--text-primary);font-size:.9rem;font-weight:600}.email-date{color:var(--text-muted);font-size:.8rem;flex-shrink:0;font-weight:600}.email-subject{color:var(--text-primary);font-size:.95rem;margin-bottom:.25rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.email-preview{color:var(--text-muted);font-size:.85rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}@keyframes toastSlideIn{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.toast-undo{display:flex;align-items:center;gap:1rem}.undo-message{flex:1}.undo-btn{padding:.25rem .75rem;background:var(--accent-blue);color:var(--text-on-accent);border:2px solid var(--border-color);border-radius:var(--radius-sm);font-family:inherit;font-size:var(--font-size-sm);font-weight:600;cursor:pointer;transition:background .15s ease}.undo-btn:hover{background:color-mix(in srgb,var(--accent-blue) 80%,#000)}.undo-countdown{font-size:var(--font-size-sm);color:var(--text-muted);min-width:2.5rem;text-align:right}@keyframes modalFadeIn{from{opacity:0}to{opacity:1}}@keyframes modalSlideIn{from{opacity:0;transform:translateY(-20px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes modalFadeOut{from{opacity:1}to{opacity:0}}@keyframes modalSlideOut{from{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:translateY(-20px) scale(.95)}}.modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background-color:var(--overlay-color);display:flex;align-items:center;justify-content:center;z-index:1000;animation:modalFadeIn .15s ease-out}.modal-overlay.hidden{display:none}.modal-overlay.closing{animation:modalFadeOut .15s ease-in forwards}.modal-container{background-color:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-lg);box-shadow:var(--shadow-brutal-xl);max-width:var(--width-modal);width:90%;max-height:90vh;overflow:auto;animation:modalSlideIn .2s ease-out}.modal-container.modal-large{max-width:calc(100vw - 4rem);width:calc(100vw - 4rem);max-height:calc(100vh - 4rem);height:calc(100vh - 4rem);display:flex;flex-direction:column}.modal-container.modal-large .modal-content{flex:1;overflow:auto;display:flex;flex-direction:column}.modal-overlay.closing .modal-container{animation:modalSlideOut .15s ease-in forwards}.modal-header{display:flex;justify-content:space-between;align-items:center;padding:1rem 1.5rem;border-bottom:var(--border-width) solid var(--border-color);background:var(--bg-secondary)}.modal-header h2,.modal-title{font-family:var(--font-heading);font-size:1.25rem;font-weight:700}.modal-close{background:var(--bg-card);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm);font-size:1.25rem;color:var(--text-primary);cursor:pointer;line-height:1;width:36px;height:36px;display:flex;align-items:center;justify-content:center;transition:background-color .15s ease}.modal-close:hover{background:var(--accent-blue);color:var(--text-on-accent)}.modal-content{padding:1.5rem}.form-group{margin-bottom:1.25rem}.form-label{display:block;font-size:.9rem;font-weight:700;color:var(--text-primary);margin-bottom:.5rem}.form-input,.form-select,.form-textarea{width:100%;padding:.75rem 1rem;border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm);background-color:var(--bg-card);color:var(--text-primary);font-size:1rem;box-shadow:none}.form-input:focus,.form-select:focus,.form-textarea:focus{outline:0;background-color:var(--bg-card);box-shadow:0 0 0 2px var(--accent-blue)}.form-textarea{min-height:100px;resize:vertical}.form-actions{display:flex;justify-content:flex-end;gap:.75rem;margin-top:1.5rem}.form-input[aria-invalid=true],.form-select[aria-invalid=true],.form-textarea[aria-invalid=true]{border-color:var(--accent-red);box-shadow:0 0 0 2px color-mix(in srgb,var(--accent-red) 30%,transparent)}.form-input[aria-invalid=true]:focus,.form-select[aria-invalid=true]:focus,.form-textarea[aria-invalid=true]:focus{box-shadow:0 0 0 2px var(--accent-red)}.form-error{color:var(--accent-red);font-size:.8rem;font-weight:600;margin-top:.25rem;display:none}.form-error.visible{display:block}.app-footer{background-color:var(--bg-card);border-top:var(--border-width) solid var(--border-color);padding:.75rem 1.5rem}.footer-content{max-width:var(--width-container);margin:0 auto;display:flex;justify-content:space-between;align-items:center}.keyboard-hints{display:flex;gap:1rem;font-size:.8rem;color:var(--text-muted)}kbd{display:inline-block;padding:.2rem .5rem;background-color:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-xs);font-family:var(--font-mono);font-size:.75rem;font-weight:700}.version{font-size:.75rem;color:var(--text-muted);font-weight:600}.empty-state{text-align:center;padding:3rem;color:var(--text-secondary)}.empty-state-icon{font-size:4rem;margin-bottom:1rem}.empty-state-text{font-size:1.1rem;font-weight:600;margin-bottom:1rem}.error-state{text-align:center;padding:2rem;color:var(--accent-red);background:color-mix(in srgb,var(--accent-red) 10%,var(--bg-card));border:var(--border-width-sm) solid var(--accent-red);border-radius:var(--radius-sm);font-weight:600}.view{display:block}.view.hidden{display:none}.filter-bar{display:flex;flex-wrap:wrap;gap:.75rem;margin-bottom:1.5rem;padding:1rem;background-color:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.filter-group{display:flex;align-items:center;gap:.5rem}.filter-label{font-size:.8rem;font-weight:700;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.05em}.filter-select{padding:.5rem .75rem;border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm);background-color:var(--bg-card);color:var(--text-primary);font-size:.875rem;font-weight:600}.filter-select:focus{outline:0;background-color:var(--accent-blue);color:var(--text-on-accent)}.filter-checkbox{display:flex;align-items:center;gap:.4rem;font-size:.875rem;font-weight:600;color:var(--text-primary);cursor:pointer}.filter-checkbox input[type=checkbox]{width:1rem;height:1rem;cursor:pointer}.btn-link{background:0 0;border:none;box-shadow:none;color:var(--text-secondary);font-size:.875rem;cursor:pointer;text-decoration:underline;padding:.5rem}.btn-link:hover{box-shadow:none;transform:none;color:var(--text-primary)}@media (min-width:1400px){.main-content{max-width:1600px}.cards-grid{grid-template-columns:repeat(auto-fill,minmax(380px,1fr))}.project-dashboard-grid{gap:2rem}.day-plan-sidebar{width:320px}.modal-container{max-width:640px}}@media (max-width:1024px){.saved-views-sidebar{width:180px}.day-plan-sidebar{width:240px}.project-dashboard-grid{grid-template-columns:1fr 1fr;gap:1rem}.project-dashboard-grid .dashboard-column:last-child{grid-column:span 2}.filter-bar{flex-wrap:wrap}.filter-actions{width:100%;justify-content:flex-end;margin-top:.5rem}}@media (max-width:768px){.tab-navigation{flex-wrap:wrap;gap:.5rem}.tab{flex:1 1 auto;min-width:calc(33% - .5rem);justify-content:center;padding:.625rem .75rem}.tab-label{display:none}.tab-icon{font-size:1.25rem}.cards-grid{grid-template-columns:1fr}.task-table{font-size:.85rem}.task-header-row,.task-row{grid-template-columns:1fr 80px 40px 80px}.task-header-row .task-cell:nth-child(n+5),.task-row .task-cell:nth-child(n+5){display:none}.filter-bar{flex-direction:column}.keyboard-hints{display:none}.page-title{font-size:1.5rem}.saved-views-sidebar{display:none}.day-plan-content{flex-direction:column}.day-plan-sidebar{width:100%;max-height:200px}.project-dashboard-grid{grid-template-columns:1fr}.project-dashboard-grid .dashboard-column:last-child{grid-column:span 1}.modal-container{width:95%;max-height:95vh}.bulk-actions-bar{flex-wrap:wrap}.bulk-select-all{width:100%;margin-top:.5rem}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pagination-controls{display:flex;align-items:center;justify-content:center;gap:1rem;padding:1rem;margin-top:1rem;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md)}.pagination-info{font-weight:600;color:var(--text-secondary);font-size:.9rem}.pagination-controls .btn:disabled{opacity:.5;cursor:not-allowed}.btn:focus-visible,.card:focus-visible,.dashboard-item:focus-visible,.email-item:focus-visible,.event-row-virtual:focus-visible,.filter-select:focus-visible,.form-input:focus-visible,.form-select:focus-visible,.form-textarea:focus-visible,.modal-close:focus-visible,.saved-view-item:focus-visible,.snooze-option:focus-visible,.tab:focus-visible,.task-row:focus-visible,.timeline-item:focus-visible,.unscheduled-task:focus-visible{outline:3px solid var(--accent-blue);outline-offset:2px}.event-row,.task-row-clickable{cursor:pointer}.skip-link{position:absolute;top:-100px;left:0;background:var(--accent-blue);color:var(--text-on-accent);padding:.75rem 1.5rem;z-index:9999;font-weight:700;border:var(--border-width) solid var(--border-color);text-decoration:none}.skip-link:focus{top:0}.source-email-link{padding:.75rem;background:var(--bg-secondary);border-radius:var(--radius-sm);border-left:4px solid var(--accent-blue)}.thread-message{margin-bottom:1rem;padding:.75rem;background:var(--bg-secondary);border-radius:var(--radius-sm)}.thread-message-latest{border-left:3px solid var(--accent-blue)}.thread-message-header{display:flex;justify-content:space-between;margin-bottom:.5rem;font-size:.8rem;color:var(--text-secondary)}.thread-message-from{font-weight:700}.email-reader-body{white-space:pre-wrap;font-size:.9rem;line-height:1.6;color:var(--text-primary);word-wrap:break-word;overflow-wrap:break-word}.email-reader-body .email-link{color:var(--accent-blue);text-decoration:underline;cursor:pointer;word-break:break-all}.email-reader-body .email-link:hover{color:var(--accent-cyan)}.email-reader-body hr{border:none;border-top:2px solid var(--border-color);margin:1rem 0}.email-reader-quote{border-left:3px solid var(--text-muted);padding-left:1rem;margin:.5rem 0;color:var(--text-secondary);font-style:italic}.email-reader-container{display:flex;flex-direction:column;height:100%;min-height:0}.email-reader-header{margin-bottom:1rem;padding-bottom:.75rem;border-bottom:1px solid var(--border-color)}.email-sender-contact{display:flex;align-items:center;gap:.5rem;margin-top:.5rem;padding:.4rem .5rem;background:var(--bg-tertiary);border-radius:4px}.email-sender-info{display:flex;flex-direction:column;flex:1;min-width:0}.email-sender-name{font-weight:600;font-size:.85rem}.email-sender-company{font-size:.75rem;color:var(--text-secondary)}.contact-avatar-sm{width:32px;height:32px;border-radius:50%;background:var(--accent-color);color:var(--bg-primary);display:flex;align-items:center;justify-content:center;font-size:.75rem;font-weight:700;flex-shrink:0}.contact-avatar-unknown{background:var(--bg-secondary);color:var(--text-secondary);border:var(--border-width-sm) solid var(--border-color)}.email-reader-thread{flex:1;overflow-y:auto;margin-bottom:1rem;min-height:0}.dropdown{position:relative;display:inline-block}.dropdown-menu{display:none;position:absolute;bottom:100%;left:0;margin-bottom:.25rem;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);box-shadow:var(--shadow-brutal-md);min-width:160px;z-index:100}.dropdown-menu.show{display:block}.dropdown-item{display:block;width:100%;padding:.5rem 1rem;text-align:left;background:0 0;border:none;cursor:pointer;font-size:.875rem;color:var(--text-primary)}.dropdown-item:hover{background:var(--bg-secondary)}.dropdown-item:first-child{border-radius:var(--radius-md) var(--radius-md) 0 0}.dropdown-item:last-child{border-radius:0 0 var(--radius-md) var(--radius-md)}.context-menu{position:fixed;z-index:10000;min-width:180px;max-width:280px;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-sm);box-shadow:var(--shadow-brutal-lg);padding:.25rem 0;display:none}.context-menu.visible{display:block}.context-menu-item{display:flex;align-items:center;gap:.75rem;padding:.5rem 1rem;font-size:.875rem;font-weight:500;color:var(--text-primary);cursor:pointer;border:none;background:0 0;width:100%;text-align:left;transition:background .1s}.context-menu-item:focus,.context-menu-item:hover{background:var(--accent-blue);color:var(--text-on-accent);outline:0}.context-menu-item:focus-visible{outline:2px solid var(--accent-blue);outline-offset:-2px}.context-menu-item-icon{width:1.25rem;text-align:center;flex-shrink:0}.context-menu-item-label{flex:1}.context-menu-item-shortcut{font-size:.75rem;color:var(--text-muted);font-family:var(--font-mono)}.context-menu-item--danger{color:var(--accent-red)}.context-menu-item--danger:hover{background:var(--accent-red);color:var(--text-on-accent)}.context-menu-separator{height:2px;background:var(--border-color);margin:.25rem .5rem}.context-menu-hint{padding:.35rem 1rem;font-size:.7rem;color:var(--text-muted);border-top:1px solid var(--border-color);margin-top:.25rem}::-webkit-scrollbar{width:12px;height:12px}::-webkit-scrollbar-track{background:var(--bg-secondary);border-left:2px solid var(--border-color)}::-webkit-scrollbar-thumb{background:var(--text-muted);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm)}::-webkit-scrollbar-thumb:hover{background:var(--text-secondary)}.loading{display:flex;justify-content:center;align-items:center;height:200px;color:var(--text-secondary);font-family:var(--font-heading)}.skeleton-shimmer{display:flex;flex-direction:column;gap:1rem;padding:1rem}.skeleton-shimmer .skeleton-row{display:flex;align-items:center;gap:.75rem;padding:.75rem;background:var(--bg-card);border-radius:var(--radius-md);border:var(--border-width) solid var(--border-color)}.skeleton-shimmer .skeleton-avatar{width:36px;height:36px;border-radius:var(--radius-full);background:linear-gradient(90deg,var(--bg-secondary) 25%,var(--bg-tertiary) 50%,var(--bg-secondary) 75%);background-size:200% 100%;animation:skeleton-pulse 1.5s ease-in-out infinite;flex-shrink:0}.skeleton-shimmer .skeleton-lines{flex:1;display:flex;flex-direction:column;gap:.4rem}.skeleton-shimmer .skeleton-line{height:.75rem;border-radius:var(--radius-sm);background:linear-gradient(90deg,var(--bg-secondary) 25%,var(--bg-tertiary) 50%,var(--bg-secondary) 75%);background-size:200% 100%;animation:skeleton-pulse 1.5s ease-in-out infinite}.skeleton-shimmer .skeleton-line.short{width:40%}.skeleton-shimmer .skeleton-line.medium{width:65%}.skeleton-shimmer .skeleton-line.long{width:90%}@keyframes skeleton-pulse{0%{background-position:200% 0}100%{background-position:-200% 0}}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}.spinner{display:inline-block;width:1em;height:1em;border:2px solid currentColor;border-top-color:transparent;border-radius:var(--radius-full);animation:spin .8s linear infinite}.btn-loading{position:relative;pointer-events:none;opacity:.8}.btn-loading .btn-text{visibility:hidden}.btn-loading::after{content:'';position:absolute;left:50%;top:50%;width:1em;height:1em;margin-left:-.5em;margin-top:-.5em;border:2px solid currentColor;border-top-color:transparent;border-radius:var(--radius-full);animation:spin .8s linear infinite}.hidden{display:none!important}.project-dashboard-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1.5rem;flex:1;min-height:0}.dashboard-column{background:var(--bg-card);border:var(--border-width) solid var(--border-color);padding:1rem;display:flex;flex-direction:column;overflow:hidden}.dashboard-column-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem;padding-bottom:.5rem;border-bottom:2px solid var(--border-color)}.dashboard-column-header h3{margin:0;font-size:1rem;font-family:var(--font-heading);font-weight:700}.dashboard-list{flex:1;overflow-y:auto}.dashboard-item{padding:.75rem;background:var(--bg-card);border:var(--border-width-sm) solid var(--border-color);margin-bottom:.5rem;cursor:pointer;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color);transition:transform .15s ease,box-shadow .15s ease,background-color .15s ease}.dashboard-item:hover{background:var(--bg-secondary);transform:translate(-2px,-2px);box-shadow:calc(var(--shadow-offset) + 2px) calc(var(--shadow-offset) + 2px) 0 var(--border-color)}.dashboard-item-title{font-weight:600;margin-bottom:.25rem}.dashboard-item-meta{font-size:.75rem;color:var(--text-secondary)}.empty-dashboard-list{text-align:center;padding:2rem 1rem;color:var(--text-secondary)}.task-badges{display:flex;gap:.25rem;margin-top:.25rem}.task-badge{font-size:.65rem;padding:.15rem .4rem;border:var(--border-width-sm) solid var(--border-color);background:var(--bg-secondary);color:var(--text-primary);font-weight:600}.task-badge.has-items{background:var(--accent-blue);color:var(--text-on-accent)}.task-badge.recurrence{background:var(--accent-purple);color:var(--text-on-accent)}.task-row-clickable{cursor:pointer;transition:background .1s}.task-row-clickable:hover{background:var(--bg-secondary)}.progress-bar-container{width:100%;height:10px;background:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);overflow:hidden}.progress-bar{height:100%;background:var(--accent-green);transition:width .3s ease}.no-subtasks{color:var(--text-secondary);font-size:.875rem}#day-plan-view{display:flex;flex-direction:column;flex:1;min-height:0}#day-plan-view .page-header{flex-shrink:0}.day-plan-nav{display:flex;align-items:center;gap:.5rem}.day-plan-date-picker{padding:.5rem;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-sm);color:var(--text-primary);font-family:var(--font-body)}.day-plan-date-display{font-size:1.25rem;font-weight:700;margin-left:1rem;font-family:var(--font-heading);line-height:1}.day-plan-content{flex:1;min-height:0;display:flex;gap:1.5rem}.day-plan-main{flex:1;min-height:0;display:flex;flex-direction:column;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);overflow:hidden;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.day-plan-sidebar{width:280px;flex-shrink:0;display:flex;flex-direction:column;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);overflow:hidden;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.sidebar-header{padding:1rem;border-bottom:2px solid var(--border-color);flex-shrink:0}.sidebar-header h3{margin:0;font-size:1rem;font-family:var(--font-heading);font-weight:700}.sidebar-task-list{flex:1;overflow-y:auto;padding:.75rem;display:flex;flex-direction:column;gap:.5rem}.timeline-container{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden}.timeline-scroll-area{position:relative;padding:.5rem 1rem 3rem .5rem;min-height:min-content}#timeline-slots{position:relative}#timeline-items{position:absolute;top:.5rem;left:.5rem;right:1rem;bottom:0;pointer-events:none}#timeline-items .timeline-item{pointer-events:auto}.timeline-slot{display:grid;grid-template-columns:50px 1fr;height:12px;position:relative}.timeline-slot.hour-start .timeline-slot-area{border-top:1px dashed color-mix(in srgb,var(--border-color) 50%,transparent)}.timeline-time{font-size:.7rem;color:var(--text-secondary);padding-right:.5rem;text-align:right;font-weight:500;transform:translateY(-.5em)}.timeline-slot-area{position:relative}.timeline-slot-area:hover{background:var(--bg-secondary)}.timeline-item{position:absolute;left:60px;right:10px;border:var(--border-width) solid var(--border-color);border-radius:var(--radius-sm);padding:.25rem .5rem;overflow:hidden;cursor:pointer;z-index:10}.timeline-item.task{background:var(--accent-green);color:var(--text-primary)}.timeline-item.event{background:var(--accent-blue);color:var(--text-on-accent)}.timeline-item.block{opacity:.85}.timeline-item.block-free_time{background:var(--accent-cyan);color:var(--text-primary)}.timeline-item.block-personal{background:var(--accent-yellow);color:var(--text-primary)}.timeline-item.block-vacation{background:var(--accent-purple);color:var(--text-on-accent)}.timeline-item.block-focus{background:var(--accent-red);color:var(--text-on-accent)}.timeline-item.conflict{box-shadow:0 0 0 3px var(--accent-red)}.timeline-item.selected{box-shadow:0 0 0 3px var(--bg-card),0 0 0 6px var(--accent-blue)}.timeline-item-title{font-weight:600;font-size:.75rem;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.timeline-item-meta{font-size:.65rem;opacity:.85;line-height:1.1}.timeline-current-time{position:absolute;left:50px;right:0;height:2px;background:var(--accent-red);z-index:20;pointer-events:none}.timeline-current-time::before{content:'';position:absolute;left:-4px;top:-3px;width:8px;height:8px;background:var(--accent-red);border-radius:var(--radius-full)}.timeline-paint-preview{position:absolute;left:70px;right:10px;background:var(--accent-blue);opacity:.4;border:var(--border-width-sm) dashed var(--border-color);border-radius:var(--radius-sm);z-index:5;pointer-events:none}.timeline-container.is-painting{cursor:crosshair;user-select:none}.timeline-container.is-painting .timeline-slot-area{pointer-events:none}.unscheduled-task{padding:.75rem;background:var(--bg-card);border:var(--border-width-sm) solid var(--border-color);border-left:6px solid var(--accent-green);border-radius:var(--radius-sm);cursor:grab;transition:background-color .1s}.unscheduled-task:hover{background:var(--bg-secondary)}.unscheduled-task.priority-high{border-left-color:var(--accent-red)}.unscheduled-task.priority-medium{border-left-color:var(--accent-yellow)}.unscheduled-task.priority-low{border-left-color:var(--accent-green)}.unscheduled-task-title{font-weight:600;margin-bottom:.25rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.unscheduled-task-meta{font-size:.75rem;color:var(--text-secondary)}.empty-unscheduled{text-align:center;color:var(--text-secondary);padding:2rem 1rem}.settings-btn{background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-sm);color:var(--text-primary);font-size:1.25rem;cursor:pointer;padding:.5rem .75rem;margin-left:.5rem;transition:background-color .1s}.settings-btn:hover{background:var(--bg-secondary)}.settings-btn:active{background:var(--bg-tertiary)}.shortcut-hint-btn{font-family:var(--font-mono, monospace);font-weight:700;min-width:2rem;text-align:center;padding:.5rem}.settings-section h3{font-size:1rem;color:var(--text-primary)}.settings-section .form-hint{font-size:.75rem;color:var(--text-secondary)}.llm-settings-form .form-group{margin-bottom:1rem}.llm-settings-form .form-row{display:grid;grid-template-columns:1fr 1fr;gap:1rem}.llm-settings-form .form-hint{font-size:.75rem;color:var(--text-secondary);margin-top:.25rem}.llm-settings-form .slider-value{font-weight:700;color:var(--accent-blue)}.llm-test-result{padding:.75rem;border:var(--border-width) solid var(--border-color);margin-top:1rem}.llm-test-result.success{background:var(--accent-green);color:var(--text-primary)}.llm-test-result.error{background:var(--accent-red);color:var(--text-on-accent)}.llm-cache-info{margin-top:1rem;padding-top:1rem;border-top:2px solid var(--border-color)}.sync-indicator{background:0 0;border:none;cursor:pointer;padding:.25rem .5rem;display:flex;align-items:center}.sync-dot{width:8px;height:8px;border-radius:var(--radius-full);background:var(--text-muted);transition:background var(--transition-slow)}.sync-dot.connected{background:var(--accent-green)}.sync-dot.syncing{background:var(--accent-blue);animation:sync-pulse 1s infinite}.sync-dot.error{background:var(--accent-red)}@keyframes sync-pulse{0%,100%{opacity:1}50%{opacity:.4}}.snooze-options{display:flex;flex-direction:column;gap:.5rem}.snooze-option{display:flex;justify-content:space-between;align-items:center;padding:.75rem 1rem;background:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);color:var(--text-primary);cursor:pointer;transition:background-color .1s;text-align:left;width:100%}.snooze-option:hover{background:var(--accent-blue);color:var(--text-on-accent)}.snooze-option-label{font-weight:600}.snooze-option-time{font-size:.75rem;color:var(--text-secondary)}.snooze-option:hover .snooze-option-time{color:var(--text-on-accent)}.snooze-custom{margin-top:.5rem;padding-top:.5rem;border-top:2px solid var(--border-color)}.snooze-badge{display:inline-block;font-size:.65rem;padding:.15rem .4rem;border:var(--border-width-sm) solid var(--border-color);background:var(--accent-yellow);color:var(--text-primary);font-weight:700;margin-top:.25rem}.contact-badge{display:inline-block;font-size:.65rem;padding:.15rem .4rem;border:var(--border-width-sm) solid var(--border-color);background:var(--accent-color);color:var(--bg-primary);font-weight:700;margin-top:.25rem}.bulk-checkbox{width:18px;height:18px;cursor:pointer;accent-color:var(--accent-blue);border:var(--border-width-sm) solid var(--border-color)}.task-actions-cell{text-align:right;white-space:nowrap;display:flex;align-items:center;justify-content:flex-end;gap:.5rem}.task-actions-cell .bulk-checkbox{margin-right:.5rem}.task-recurrence{font-size:.85rem;color:var(--text-secondary)}.task-due{white-space:nowrap}.bulk-actions-bar{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem;background:var(--accent-blue);color:var(--text-on-accent);border:var(--border-width) solid var(--border-color);box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color);margin-bottom:1rem;color:var(--text-primary)}.bulk-actions-bar.hidden{display:none}.bulk-count{font-weight:700;margin-right:1rem;font-family:var(--font-heading)}.bulk-actions-bar .btn{background:var(--bg-card);border:var(--border-width-sm) solid var(--border-color);color:var(--text-primary)}.bulk-actions-bar .btn:hover{background:var(--bg-secondary)}.bulk-select-all{margin-left:auto}.email-checkbox-cell{padding:.75rem .5rem;display:flex;align-items:center}.email-item-with-checkbox{display:flex;align-items:flex-start}.email-item-with-checkbox .email-content{flex:1}.schedule-task-btn{display:flex;align-items:center;gap:.5rem}.time-block-form{display:flex;flex-direction:column;gap:1rem}.time-block-quick-options{display:grid;grid-template-columns:repeat(3,1fr);gap:.5rem}.time-block-quick-btn{padding:.5rem;background:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);color:var(--text-primary);cursor:pointer;font-size:.875rem;font-weight:600;transition:background-color .1s}.time-block-quick-btn:hover{background:var(--bg-tertiary)}.time-block-quick-btn.selected{background:var(--accent-blue);color:var(--text-on-accent);box-shadow:inset 0 0 0 2px var(--border-color)}.duration-presets{display:flex;gap:.5rem;flex-wrap:wrap}.duration-preset{padding:.35rem .75rem;background:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);color:var(--text-primary);cursor:pointer;font-size:.75rem;font-weight:600;transition:background-color .1s}.duration-preset:hover{background:var(--bg-tertiary)}.duration-preset.selected{background:var(--accent-blue);color:var(--text-on-accent)}.conflict-warning{padding:.75rem;background:var(--accent-red);border:var(--border-width) solid var(--border-color);color:var(--text-on-accent);font-size:.875rem;font-weight:600;margin-top:.5rem}.app-body{display:flex;flex:1;min-height:0;overflow:hidden}.app-body .main-content{flex:1;min-width:0;display:flex;flex-direction:column;overflow-x:visible;overflow-y:auto}#emails-view,#events-view,#projects-view,#tasks-view{padding-bottom:2.5rem}#tasks-view{display:flex;flex-direction:column;flex:1;min-height:0}#tasks-view .bulk-actions-bar,#tasks-view .filter-bar,#tasks-view .page-header{flex-shrink:0}#events-view{display:flex;flex-direction:column;flex:1;min-height:0}#events-view .page-header{flex-shrink:0}#emails-view{display:flex;flex-direction:column;flex:1;min-height:0}#emails-view .bulk-actions-bar,#emails-view .page-header{flex-shrink:0}.saved-views-sidebar{width:200px;flex-shrink:0;background:var(--bg-card);border-right:var(--border-width) solid var(--border-color);display:flex;flex-direction:column;overflow:hidden}.sidebar-section{display:flex;flex-direction:column;flex:1;min-height:0}.sidebar-section-header{display:flex;justify-content:space-between;align-items:center;padding:.75rem 1rem;font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--text-secondary);border-bottom:2px solid var(--border-color);background:var(--bg-secondary)}.btn-icon{background:0 0;border:none;color:var(--text-muted);cursor:pointer;padding:.25rem;font-size:.875rem;line-height:1}.btn-icon:hover{color:var(--text-primary)}.pinned-views-list{flex:1;overflow-y:auto;padding:.5rem}.sidebar-empty{text-align:center;padding:1.5rem .5rem;color:var(--text-muted);font-size:.8rem}.saved-view-item{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;margin-bottom:.5rem;background:var(--bg-card);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm);cursor:pointer;font-size:.85rem;font-weight:600;color:var(--text-primary);box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color);transition:transform .15s ease,box-shadow .15s ease,background-color .15s ease,color .15s ease}.saved-view-item:hover{background:var(--accent-blue);color:var(--text-on-accent)}.saved-view-item.active{background:var(--accent-blue);color:var(--text-on-accent);box-shadow:inset 0 0 0 2px var(--border-color)}.saved-view-item .view-icon{font-size:.75rem}.saved-view-item .view-name{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.saved-view-item .view-actions{opacity:0;transition:opacity .1s}.saved-view-item:hover .view-actions{opacity:1}.filter-actions{display:flex;gap:.5rem;margin-left:auto}.contact-avatar{width:40px;height:40px;min-width:40px;border-radius:50%;background-color:var(--accent-blue);color:var(--text-on-accent);display:flex;align-items:center;justify-content:center;font-weight:700;font-size:.85rem;font-family:var(--font-heading);border:2px solid var(--border-color)}.contact-avatar-lg{width:60px;height:60px;min-width:60px;font-size:1.2rem}.contact-card .card-header{display:flex;align-items:center}.contact-nickname{display:block;font-size:.85rem;color:var(--text-secondary);font-style:italic}.contact-company{display:block;font-size:.85rem;color:var(--text-secondary)}.contact-email{font-size:.85rem;color:var(--text-secondary)}.contact-detail .detail-row{margin-bottom:.5rem;font-size:.9rem}.contact-detail .contact-info-section{margin-bottom:1rem;padding-bottom:1rem;border-bottom:1px solid var(--border-light,#e0e0e0)}.contact-detail .contact-notes{margin-bottom:1.5rem}.contact-detail .contact-notes p{margin-top:.25rem;white-space:pre-wrap;color:var(--text-secondary)}.sub-collection{margin-bottom:1.25rem}.sub-collection-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.5rem}.sub-collection-header h4{margin:0;font-size:.95rem;font-weight:600}.sub-item{display:flex;justify-content:space-between;align-items:center;padding:.4rem 0;border-bottom:1px solid var(--border-light,#e0e0e0);font-size:.9rem}.sub-item:last-child{border-bottom:none}.sub-empty{font-size:.85rem;color:var(--text-secondary);font-style:italic;padding:.25rem 0}.edit-sub-collections{border-top:1px solid var(--border-color);padding-top:1rem;margin-bottom:.5rem}.edit-sub-section{margin-bottom:.75rem}.edit-sub-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.25rem}.sub-item-compact{font-size:.85rem;color:var(--text-secondary);padding:.125rem 0}@media print{.btn,.context-menu,.filter-bar,.keyboard-hints,.modal-overlay,.pagination,.sidebar,.tabs,.toast{display:none!important}body{background:#fff;color:#000}.main-content{margin:0;padding:0;max-width:100%}.view{padding:0}.data-table{border:1px solid #333;box-shadow:none}.data-table td,.data-table th{border:1px solid #ccc;padding:.5rem}.data-table td,.data-table th{display:table-cell!important}.data-table tbody tr:hover{background:0 0}.task-table{border:1px solid #333;box-shadow:none}.task-list-container{height:auto!important;overflow:visible!important}.task-header-row,.task-row{grid-template-columns:1fr 100px 40px 80px 60px 80px 60px!important}.task-header-row .task-cell,.task-row .task-cell{display:block!important;border:1px solid #ccc;padding:.25rem .5rem}.task-row:hover{background:0 0}.virtual-scroller-spacer-bottom,.virtual-scroller-spacer-top{display:none!important}a{color:#000;text-decoration:underline}.view-header{page-break-after:avoid}.data-table{page-break-inside:avoid}}.weekly-review-content{max-width:900px;margin:0 auto;padding:1rem}.weekly-review-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1.5rem;padding-bottom:1rem;border-bottom:var(--border-width-sm) solid var(--border-color)}.week-info{display:flex;align-items:center;gap:1rem}.week-dates{font-family:var(--font-heading);font-size:1.25rem;font-weight:700;color:var(--text-primary)}.review-status{padding:.25rem .75rem;border-radius:var(--radius-xs);font-size:.875rem;font-weight:600;border:var(--border-width-sm) solid var(--border-color)}.review-status.completed{background:var(--accent-green);color:var(--text-on-accent)}.review-status.pending{background:var(--accent-yellow);color:var(--text-primary)}.stat-cards{display:flex;gap:1rem;margin-bottom:1rem;flex-wrap:wrap}.stat-card{flex:1;min-width:100px;max-width:150px;padding:1rem;background:var(--bg-card);border:var(--border-width) solid var(--border-color);text-align:center;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.stat-card .stat-number{display:block;font-family:var(--font-heading);font-size:2rem;font-weight:700;color:var(--accent-blue);line-height:1}.stat-card .stat-label{display:block;font-size:.75rem;font-weight:600;color:var(--text-muted);margin-top:.25rem;text-transform:uppercase;letter-spacing:.5px}.stat-card.stat-warning .stat-number{color:var(--accent-yellow)}.stat-card.stat-danger .stat-number{color:var(--accent-red)}.review-section{background:var(--bg-card);border:var(--border-width) solid var(--border-color);padding:1.25rem;margin-bottom:1.5rem;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.section-title{font-family:var(--font-heading);font-size:1.125rem;font-weight:700;color:var(--text-primary);margin-bottom:1rem;padding-bottom:.5rem;border-bottom:var(--border-width-sm) solid var(--border-color)}.review-details{margin-top:.75rem}.review-details summary{cursor:pointer;font-weight:600;color:var(--text-secondary);padding:.5rem;background:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);user-select:none}.review-details summary:hover{background:var(--bg-tertiary)}.review-details[open] summary{margin-bottom:.5rem}.review-event-list,.review-task-list{list-style:none;padding:0;margin:0}.review-event-item,.review-task-item{display:flex;align-items:center;gap:.75rem;padding:.5rem .75rem;border-bottom:1px solid var(--border-color)}.review-event-item:last-child,.review-task-item:last-child{border-bottom:none}.review-event-item .event-title,.review-task-item .task-description{flex:1;color:var(--text-primary)}.event-time{font-size:.875rem;font-weight:600;color:var(--text-muted);min-width:80px}.project-badge{font-size:.75rem;padding:.125rem .5rem;background:var(--bg-tertiary);border:1px solid var(--border-color);color:var(--text-secondary)}.due-badge{font-size:.75rem;padding:.125rem .5rem;background:var(--bg-secondary);border:1px solid var(--border-color);color:var(--text-secondary)}.due-badge.overdue{background:var(--accent-red);color:var(--text-on-accent);border-color:var(--accent-red)}.focus-section{background:linear-gradient(135deg,var(--bg-card) 0,color-mix(in srgb,var(--accent-yellow) 15%,var(--bg-card)) 100%)}.focus-task-list{list-style:none;padding:0;margin:0 0 1rem 0}.focus-task-list.available{opacity:.8}.focus-toggle{background:0 0;border:none;font-size:1.25rem;cursor:pointer;color:var(--text-muted);padding:0;line-height:1;transition:transform .15s ease}.focus-toggle:hover{transform:scale(1.2)}.focus-toggle.focused{color:var(--accent-yellow)}.review-task-item.focused{background:color-mix(in srgb,var(--accent-yellow) 10%,var(--bg-card))}.no-focus-message{color:var(--text-muted);font-style:italic;margin-bottom:1rem}.focused-projects{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}.project-tag{background:var(--accent-blue);color:var(--text-on-accent);padding:.25rem .75rem;font-size:.875rem;font-weight:600;border:var(--border-width-sm) solid var(--border-color)}.notes-section{background:var(--bg-card)}.review-notes-input{width:100%;padding:.75rem;font-family:var(--font-mono);font-size:.9rem;border:var(--border-width-sm) solid var(--border-color);background:var(--bg-secondary);color:var(--text-primary);resize:vertical;min-height:100px}.review-notes-input:focus{outline:0;background:var(--bg-card);box-shadow:inset 0 0 0 2px var(--accent-blue)}.review-actions{margin-top:1rem;text-align:center}.tab-badge{display:inline-block;width:8px;height:8px;background:var(--accent-red);border-radius:var(--radius-full);margin-left:.5rem;vertical-align:middle;animation:pulse-badge 2s infinite}@keyframes pulse-badge{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.6;transform:scale(.8)}}.tab-status-dot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-left:.5rem;vertical-align:middle;transition:background-color .3s ease}.tab-status-dot.status-none{display:none}.tab-status-dot.status-green{background-color:var(--accent-green)}.tab-status-dot.status-yellow{background-color:var(--accent-yellow);animation:pulse-badge 2s ease-in-out infinite}.tab-status-dot.status-red{background-color:var(--accent-red);animation:pulse-badge 1.5s ease-in-out infinite}.review-grid{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem;max-width:1200px;margin:0 auto}.review-card{background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);padding:1.5rem;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.review-card .card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem;padding-bottom:.75rem;border-bottom:var(--border-width-sm) solid var(--bg-secondary)}.review-card .card-title{font-family:var(--font-heading);font-size:1.1rem;font-weight:700;display:flex;align-items:center;gap:.5rem}.review-card .card-icon{font-size:1.25rem}.review-card .card-badge{font-size:.8rem;padding:.25rem .75rem;border-radius:var(--radius-md);font-weight:600}.week-timeline{grid-column:1/-1}.timeline-visual{display:flex;gap:.5rem;margin-top:1rem}.timeline-day{flex:1;text-align:center;padding:.75rem .5rem;background:var(--bg-secondary);border-radius:var(--radius-md);border:1px solid var(--border-color);position:relative}.timeline-day.today{background:var(--accent-blue);color:var(--text-on-accent);border-width:2px;font-weight:700}.timeline-day.past{opacity:.7}.timeline-day.future{background:var(--bg-card)}.timeline-day .day-name{font-size:.7rem;font-weight:600;text-transform:uppercase;color:var(--text-muted)}.timeline-day .day-number{font-size:1.1rem;font-weight:700}.day-dots{display:flex;justify-content:center;gap:3px;margin-top:.5rem;min-height:8px}.day-dot{width:8px;height:8px;border-radius:var(--radius-full)}.day-dot.task{background:var(--accent-blue)}.day-dot.event{background:var(--accent-purple)}.day-dot.completed{background:var(--accent-green)}.day-dot.overdue{background:var(--accent-red)}.day-dot.vacation-off{background:var(--text-muted);opacity:.5;width:12px;height:4px;border-radius:2px}.day-events{display:flex;flex-direction:column;gap:2px;margin-top:.5rem;text-align:left}.day-event{font-size:.6rem;line-height:1.3;padding:1px 4px;border-left:2px solid var(--accent-purple);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--text-secondary)}.day-event .event-time{font-size:.55rem;font-weight:600;color:var(--accent-purple);margin-right:2px;min-width:auto}.day-event-more{font-size:.55rem;color:var(--text-muted);padding:1px 4px;font-style:italic}.week-timeline-events{grid-column:1/-1}.timeline-events-day{margin-bottom:.75rem}.timeline-events-day:last-child{margin-bottom:0}.timeline-events-day-label{font-family:var(--font-heading);font-size:.8rem;font-weight:700;color:var(--text-secondary);margin-bottom:.25rem;text-transform:uppercase}.vacation-toggles-section{margin-top:1rem;padding-top:1rem;border-top:2px solid var(--border-color)}.vacation-toggles-section h3{margin:0 0 .75rem 0;font-size:.9rem;font-family:var(--font-heading);font-weight:700}.vacation-toggles{display:flex;gap:.5rem}.vacation-toggle{width:2.5rem;height:2.5rem;border-radius:var(--radius-sm);border:var(--border-width) solid var(--border-color);background:var(--bg-secondary);font-family:var(--font-heading);font-weight:700;font-size:.8rem;cursor:pointer;transition:background var(--transition-fast),color var(--transition-fast),border-color var(--transition-fast);display:flex;align-items:center;justify-content:center}.vacation-toggle:hover{background:var(--bg-hover)}.vacation-toggle.active{background:var(--accent-purple);color:var(--text-on-accent);border-color:var(--accent-purple)}.timeline-day.vacation{opacity:.5}.timeline-day.vacation .day-name{text-decoration:line-through}.vacation-day-banner{text-align:center;padding:.5rem 1rem;background:color-mix(in srgb,var(--accent-purple) 15%,var(--bg-secondary));border:var(--border-width-sm) solid var(--accent-purple);border-radius:var(--radius-sm);font-family:var(--font-heading);font-weight:700;font-size:.85rem;color:var(--accent-purple);margin-bottom:.75rem}.stats-row{display:flex;gap:1rem;margin-bottom:1rem}.stat-box{flex:1;text-align:center;padding:1rem;background:var(--bg-secondary);border-radius:var(--radius-md)}.stat-box .stat-number{font-family:var(--font-heading);font-size:2rem;font-weight:800;line-height:1}.stat-box .stat-number.green{color:var(--accent-green)}.stat-box .stat-number.red{color:var(--accent-red)}.stat-box .stat-number.blue{color:var(--accent-blue)}.stat-box .stat-number.purple{color:var(--accent-purple)}.stat-box .stat-label{font-size:.75rem;text-transform:uppercase;color:var(--text-muted);font-weight:600;margin-top:.25rem}.task-list{list-style:none;max-height:200px;overflow-y:auto}.task-item{display:flex;align-items:center;gap:.75rem;padding:.75rem;margin-bottom:.5rem;background:var(--bg-secondary);border-radius:var(--radius-md);cursor:pointer;transition:background-color var(--transition-normal)}.task-item:hover{background:var(--accent-blue);color:var(--text-on-accent)}.task-item.completed{opacity:.6;text-decoration:line-through}.task-checkbox{width:20px;height:20px;border:2px solid var(--border-color);border-radius:var(--radius-xs);display:flex;align-items:center;justify-content:center;flex-shrink:0}.task-checkbox.checked{background:var(--accent-green);color:var(--text-on-accent)}.task-text{flex:1;font-size:.9rem}.task-project{font-size:.75rem;padding:.2rem .5rem;background:var(--bg-card);border-radius:var(--radius-xs);color:var(--text-muted)}.task-due{font-size:.75rem;color:var(--text-muted)}.task-due.overdue{color:var(--accent-red);font-weight:600}.focus-section.full-width{grid-column:1/-1}.focus-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:1rem;margin-top:1rem}.focus-slot{padding:1.25rem;background:var(--bg-secondary);border:2px dashed var(--border-color);border-radius:var(--radius-md);min-height:100px;display:flex;flex-direction:column;gap:.5rem}.focus-slot.filled{border-style:solid;background:var(--bg-card)}.focus-slot.primary{border-color:var(--accent-yellow);background:linear-gradient(135deg,var(--bg-card) 0,color-mix(in srgb,var(--accent-yellow) 10%,var(--bg-card)) 100%)}.focus-label{font-size:.7rem;text-transform:uppercase;color:var(--text-muted);font-weight:600}.focus-task{font-weight:600;font-size:.95rem}.focus-meta{font-size:.8rem;color:var(--text-secondary)}.focus-empty{color:var(--text-muted);font-style:italic;font-size:.9rem}.projects-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;margin-top:.5rem}.project-health{padding:.75rem;background:var(--bg-secondary);border-radius:var(--radius-md);border-left:4px solid var(--accent-blue)}.project-health.warning{border-left-color:var(--accent-yellow)}.project-health.danger{border-left-color:var(--accent-red)}.project-name{font-weight:600;font-size:.85rem;margin-bottom:.25rem}.project-stats{font-size:.75rem;color:var(--text-muted)}.reflection-section{grid-column:1/-1}.reflection-prompts{display:grid;grid-template-columns:1fr 1fr;gap:1rem;margin-top:1rem}.reflection-prompt{padding:1rem;background:var(--bg-secondary);border-radius:var(--radius-md)}.prompt-label{font-size:.8rem;font-weight:600;color:var(--text-secondary);margin-bottom:.5rem}.prompt-input{width:100%;padding:.75rem;border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-md);font-size:.9rem;font-family:inherit;resize:none;background:var(--bg-card)}.prompt-input:focus{outline:0;border-color:var(--accent-blue)}.review-actions-grid{grid-column:1/-1;display:flex;justify-content:flex-end;gap:1rem;padding-top:1rem}.event-item{display:flex;align-items:center;gap:.75rem;padding:.75rem;margin-bottom:.5rem;background:var(--bg-secondary);border-radius:var(--radius-md);border-left:3px solid var(--accent-purple)}.event-item .event-time{font-size:.8rem;font-weight:600;color:var(--accent-purple);min-width:100px}.event-item .event-title{flex:1;font-size:.9rem}.accomplishment-highlight{background:linear-gradient(135deg,color-mix(in srgb,var(--accent-green) 10%,var(--bg-card)) 0,color-mix(in srgb,var(--accent-green) 5%,var(--bg-card)) 100%);border:2px solid var(--accent-green);padding:1rem;border-radius:var(--radius-md);margin-bottom:1rem;display:flex;align-items:center;gap:1rem}.accomplishment-icon{font-size:2rem}.accomplishment-text{font-size:1rem}.accomplishment-text strong{color:var(--accent-green)}.task-list::-webkit-scrollbar{width:6px}.task-list::-webkit-scrollbar-track{background:var(--bg-secondary);border-radius:var(--radius-xs)}.task-list::-webkit-scrollbar-thumb{background:var(--border-color);border-radius:var(--radius-xs)}@media (max-width:900px){.review-grid{grid-template-columns:1fr}.focus-section.full-width,.reflection-section,.week-timeline,.week-timeline-events{grid-column:1}.focus-grid{grid-template-columns:1fr}.reflection-prompts{grid-template-columns:1fr}.projects-grid{grid-template-columns:1fr 1fr}}@media (max-width:600px){.stat-cards{flex-direction:column}.stat-card{max-width:none}.week-info{flex-direction:column;align-items:flex-start;gap:.5rem}.projects-grid{grid-template-columns:1fr}}.focus-slot{transition:background-color .2s ease-out,border-color .2s ease-out}.focus-slot.filled{animation:focusSlotFill .3s ease-out}@keyframes focusSlotFill{0%{transform:scale(.95);opacity:.7}100%{transform:scale(1);opacity:1}}.focus-slot:focus,.focus-slot:focus-within{outline:2px solid var(--accent-blue);outline-offset:2px}.focus-slot[tabindex]:focus{outline:2px solid var(--accent-blue);outline-offset:2px}.focus-section .btn{transition:transform .15s ease-out,opacity .15s ease-out}.focus-section .btn:active{transform:scale(.97)}@media print{.card-badge,.focus-section .btn,.focus-slot .btn,.header,.review-actions-grid,.sidebar,.tab-badge,.tab-nav,.tab-status-dot{display:none!important}.main-content,.weekly-review-content{margin:0;padding:0;width:100%;max-width:100%}.event-item,.focus-slot,.project-health,.reflection-prompt,.review-card,.weekly-review-content,body{background:#fff!important;color:#000!important;-webkit-print-color-adjust:exact;print-color-adjust:exact}.review-card{border:1px solid #ccc!important;box-shadow:none!important;page-break-inside:avoid;margin-bottom:1rem}.focus-slot{border:1px solid #999!important}.focus-slot.primary{border:2px solid #f7d154!important;background:#fffbea!important}.review-grid{display:block!important}.review-card{display:inline-block;vertical-align:top;width:48%;margin-right:2%}.focus-section.full-width,.reflection-section,.week-timeline,.week-timeline-events{width:100%!important;display:block!important}.weekly-review-header{border-bottom:2px solid #333;padding-bottom:1rem;margin-bottom:1.5rem}.week-dates{font-size:1.5rem;font-weight:700}.day-dot{-webkit-print-color-adjust:exact;print-color-adjust:exact}.day-dot.completed{background:#5cb85c!important}.day-dot.event{background:#9b59b6!important}.day-dot.overdue{background:#d9534f!important}.project-health{border-left:4px solid #337ab7!important}.project-health.warning{border-left-color:#f7d154!important}.project-health.danger{border-left-color:#d9534f!important}.focus-grid{display:flex!important;gap:1rem}.focus-slot{flex:1}.reflection-prompts{display:flex!important;gap:1rem}.reflection-prompt{flex:1}.prompt-input{border:1px solid #ccc!important;min-height:80px}.focus-section{page-break-before:auto}.reflection-section{page-break-before:always}}.monthly-review-nav{display:flex;align-items:center;gap:.5rem}.monthly-review-month-display{font-family:var(--font-heading);font-size:1.25rem;font-weight:700;color:var(--text-primary);margin-left:.5rem}.monthly-review-content{max-width:900px;margin:0 auto;padding:1rem}.month-heatmap{margin-bottom:1.5rem;border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-md);padding:1rem;background:var(--bg-secondary)}.month-heatmap-header{display:grid;grid-template-columns:repeat(7,1fr);text-align:center;margin-bottom:.5rem}.month-heatmap-day-header{font-family:var(--font-heading);font-size:.75rem;font-weight:600;color:var(--text-secondary);text-transform:uppercase}.month-heatmap-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:3px}.month-heatmap-cell{aspect-ratio:1;display:flex;flex-direction:column;align-items:center;justify-content:center;border-radius:var(--radius-xs);cursor:pointer;transition:transform .1s ease;border:var(--border-width-sm) solid transparent;position:relative;min-height:40px}.month-heatmap-cell:not(.empty):hover{transform:scale(1.1);border-color:var(--border-color);z-index:1}.month-heatmap-cell.empty{cursor:default;background:0 0}.month-heatmap-cell.intensity-0{background:var(--bg-primary)}.month-heatmap-cell.intensity-1{background:color-mix(in srgb,var(--accent-green) 20%,var(--bg-primary))}.month-heatmap-cell.intensity-2{background:color-mix(in srgb,var(--accent-green) 40%,var(--bg-primary))}.month-heatmap-cell.intensity-3{background:color-mix(in srgb,var(--accent-green) 60%,var(--bg-primary))}.month-heatmap-cell.vacation{background:var(--bg-tertiary);opacity:.6}.month-heatmap-cell.today{border-color:var(--accent-primary);border-width:2px}.month-heatmap-cell.past.intensity-0{background:var(--bg-tertiary)}.month-heatmap-day-number{font-family:var(--font-heading);font-size:.8rem;font-weight:600;color:var(--text-primary)}.month-heatmap-dots{display:flex;gap:2px;margin-top:2px}.month-dot{font-size:.6rem;font-weight:700;border-radius:var(--radius-xs);padding:0 3px;line-height:1.3}.month-dot.completed{color:var(--accent-green)}.month-dot.event{color:var(--accent-purple)}.monthly-review-cards{display:grid;grid-template-columns:1fr 1fr;gap:1rem}.review-card.month-goals-card,.review-card.month-stats-card{grid-column:span 1}.review-card.month-patterns-card,.review-card.month-pulse-card{grid-column:span 1}.review-card.month-reflection-card{grid-column:1/-1}.review-card-title{font-family:var(--font-heading);font-size:1rem;font-weight:700;margin-bottom:.75rem;color:var(--text-primary)}.month-stats-grid{display:grid;grid-template-columns:1fr 1fr;gap:.5rem}.month-stat-item{display:flex;flex-direction:column;align-items:center;padding:.5rem;border-radius:var(--radius-xs);background:var(--bg-primary);border:var(--border-width-sm) solid var(--border-color)}.month-stat-value{font-family:var(--font-heading);font-size:1.5rem;font-weight:700;color:var(--text-primary)}.month-stat-label{font-size:.75rem;color:var(--text-secondary);text-transform:uppercase;font-weight:600}.month-stats-highlights{display:flex;gap:1rem;margin-top:.5rem;justify-content:center}.stat-highlight{font-size:.8rem;color:var(--text-secondary)}.month-pulse-list{display:flex;flex-direction:column;gap:.5rem}.month-pulse-item{display:flex;align-items:center;gap:.5rem;padding:.5rem;border-radius:var(--radius-xs);background:var(--bg-primary);border:var(--border-width-sm) solid var(--border-color)}.pulse-name{font-weight:600;flex:1;font-size:.875rem}.pulse-stats{font-size:.75rem;color:var(--text-secondary)}.pulse-arrow{font-size:1rem;font-weight:700}.month-pulse-item.positive .pulse-arrow{color:var(--accent-green)}.month-pulse-item.negative .pulse-arrow{color:var(--accent-red)}.month-pulse-item.neutral .pulse-arrow{color:var(--text-secondary)}.month-goals-list{display:flex;flex-direction:column;gap:.5rem}.month-goal-item{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;border-radius:var(--radius-xs);background:var(--bg-primary);border:var(--border-width-sm) solid var(--border-color)}.month-goal-item.empty{cursor:pointer;border-style:dashed;justify-content:center}.month-goal-item.empty:hover{border-color:var(--accent-primary);background:var(--bg-secondary)}.month-goal-item.done{opacity:.7}.month-goal-item.done .month-goal-text{text-decoration:line-through}.month-goal-item.abandoned{opacity:.5}.month-goal-item.abandoned .month-goal-text{text-decoration:line-through}.month-goal-status-btn{background:0 0;border:none;cursor:pointer;font-size:1rem;padding:0;color:var(--text-secondary);width:24px;text-align:center}.month-goal-item.done .month-goal-status-btn{color:var(--accent-green)}.month-goal-item.abandoned .month-goal-status-btn{color:var(--accent-red)}.month-goal-text{flex:1;font-size:.875rem}.month-goal-delete-btn{background:0 0;border:none;cursor:pointer;color:var(--text-tertiary);padding:0 4px;font-size:.75rem;opacity:0;transition:opacity .15s}.month-goal-item:hover .month-goal-delete-btn{opacity:1}.month-goal-placeholder{color:var(--text-tertiary);font-size:.875rem}.month-reflection-fields{display:flex;flex-direction:column;gap:.5rem}.month-reflection-label{font-size:.875rem;font-weight:600;color:var(--text-secondary)}.month-reflection-textarea{width:100%;padding:.5rem;border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-xs);background:var(--bg-primary);color:var(--text-primary);font-family:var(--font-body);font-size:.875rem;resize:vertical}.month-reflection-textarea:focus{outline:2px solid var(--accent-primary);outline-offset:-1px}.month-patterns-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:.5rem}.month-pattern-item{font-size:.875rem;color:var(--text-secondary);padding:.5rem;background:var(--bg-primary);border-radius:var(--radius-xs);border:var(--border-width-sm) solid var(--border-color)}@media (max-width:640px){.monthly-review-cards{grid-template-columns:1fr}.review-card.month-goals-card,.review-card.month-patterns-card,.review-card.month-pulse-card,.review-card.month-stats-card{grid-column:span 1}.month-heatmap-cell{min-height:32px}.month-heatmap-day-number{font-size:.7rem}.month-heatmap-dots{display:none}}.import-wizard{display:flex;flex-direction:column;gap:1.5rem}.import-step{padding:1rem;background:var(--bg-secondary);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md)}.import-step h3{margin:0 0 1rem 0;font-size:var(--font-size-md);font-weight:600}.plugin-selector{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:.75rem}.plugin-option{display:flex;flex-direction:column;align-items:flex-start;padding:.75rem 1rem;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-sm);cursor:pointer;text-align:left;transition:border-color var(--transition-fast),background var(--transition-fast)}.plugin-option:hover{border-color:var(--accent-primary);background:var(--bg-hover)}.plugin-option.selected{border-color:var(--accent-primary);background:color-mix(in srgb,var(--accent-primary) 10%,var(--bg-card));box-shadow:0 0 0 2px color-mix(in srgb,var(--accent-primary) 30%,transparent)}.plugin-option .plugin-name{font-weight:600;margin-bottom:.25rem}.plugin-option .plugin-meta{display:flex;gap:.5rem;font-size:var(--font-size-sm);color:var(--text-muted);margin-bottom:.25rem}.plugin-option .plugin-extensions{color:var(--accent-cyan)}.plugin-option .plugin-types{color:var(--text-secondary)}.plugin-option .plugin-description{font-size:var(--font-size-sm);color:var(--text-secondary);line-height:1.4}.file-selector{display:flex;align-items:center;gap:1rem}.selected-file-name{color:var(--text-secondary);font-family:monospace;font-size:var(--font-size-sm)}.import-preview-container{min-height:100px}.import-preview-table-wrapper{max-height:300px;overflow:auto;border:1px solid var(--border-color);border-radius:var(--radius-sm)}.import-preview-table{font-size:var(--font-size-sm);margin:0}.import-preview-table th{position:sticky;top:0;background:var(--bg-secondary);z-index:1}.import-preview-table td{max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.import-summary{margin:0 0 .75rem 0;color:var(--text-primary)}.import-more{margin:.5rem 0 0 0;color:var(--text-muted);font-style:italic;font-size:var(--font-size-sm)}.import-empty,.import-error{padding:2rem;text-align:center;color:var(--text-muted)}.import-error{color:var(--accent-red)}.import-warnings{margin-top:1rem;padding:.75rem;background:color-mix(in srgb,var(--accent-yellow) 10%,var(--bg-card));border:1px solid var(--accent-yellow);border-radius:var(--radius-sm);font-size:var(--font-size-sm)}.import-warnings ul{margin:.5rem 0 0 1.25rem;padding:0}.import-warnings li{margin-bottom:.25rem}.plugin-list{display:flex;flex-direction:column;gap:.75rem}.plugin-item{display:flex;justify-content:space-between;align-items:center;padding:1rem;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md)}.plugin-item .plugin-info{flex:1}.plugin-item .plugin-name{font-weight:600}.plugin-item .plugin-version{color:var(--text-muted);font-size:var(--font-size-sm);margin-left:.5rem}.plugin-item .plugin-description{margin:.25rem 0;color:var(--text-secondary);font-size:var(--font-size-sm)}.plugin-item .plugin-extensions{font-size:var(--font-size-xs);color:var(--text-muted)}.plugin-item .plugin-actions{margin-left:1rem}.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(--bg-tertiary);border:2px solid var(--border-color);border-radius:var(--radius-xl);transition:background-color var(--transition-fast),border-color var(--transition-fast)}.toggle-slider:before{position:absolute;content:"";height:16px;width:16px;left:2px;bottom:2px;background-color:var(--text-muted);border-radius:var(--radius-full);transition:transform var(--transition-fast),background-color var(--transition-fast)}.toggle-switch input:checked+.toggle-slider{background-color:var(--accent-primary);border-color:var(--accent-primary)}.toggle-switch input:checked+.toggle-slider:before{transform:translateX(20px);background-color:var(--bg-card)}.toggle-switch input:focus+.toggle-slider{box-shadow:0 0 0 2px color-mix(in srgb,var(--accent-primary) 30%,transparent)}.ai-fill-wrapper{position:relative}.ai-fill-btn{position:absolute;right:.5rem;top:.5rem;font-size:.7rem;padding:.2rem .5rem;background:var(--accent-purple);color:var(--text-on-accent);border:none;border-radius:var(--radius-sm);cursor:pointer;font-family:var(--font-heading);font-weight:700;text-transform:uppercase;letter-spacing:.03em;transition:background var(--transition-fast),opacity var(--transition-fast);z-index:1}.ai-fill-btn:hover{background:color-mix(in srgb,var(--accent-purple) 80%,#000)}.ai-fill-btn:disabled{opacity:.6;cursor:wait}.milestones-section{margin-bottom:1.5rem}.milestones-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem;padding-bottom:.5rem;border-bottom:2px solid var(--border-color)}.milestones-header h3{margin:0;font-size:1rem;font-family:var(--font-heading);font-weight:700}.milestone-card{background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);padding:1rem;margin-bottom:.75rem;transition:background-color .1s;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.milestone-card:hover{background:var(--bg-secondary)}.milestone-card-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:.5rem}.milestone-card-header h4{margin:0;font-size:.95rem;font-family:var(--font-heading);font-weight:700}.milestone-card-header .milestone-status{font-size:.7rem;font-weight:700;text-transform:uppercase;padding:.15rem .4rem;border-radius:var(--radius-sm);background:var(--bg-secondary);color:var(--text-muted)}.milestone-card-header .milestone-status.completed{background:color-mix(in srgb,var(--accent-green) 15%,var(--bg-secondary));color:var(--accent-green)}.milestone-meta{display:flex;gap:1rem;font-size:.8rem;color:var(--text-muted);margin-bottom:.5rem}.milestone-progress{height:6px;background:var(--bg-secondary);border-radius:var(--radius-full);overflow:hidden;border:var(--border-width-sm) solid var(--border-color)}.milestone-progress-fill{height:100%;background:var(--accent-green);border-radius:var(--radius-full);transition:width var(--transition-fast)}.milestone-actions{display:flex;gap:.5rem;margin-top:.5rem}.milestone-actions button{font-size:.75rem;padding:.2rem .5rem;background:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm);cursor:pointer;color:var(--text-secondary);transition:background var(--transition-fast)}.milestone-actions button:hover{background:var(--bg-hover)}.milestone-actions button.danger:hover{background:color-mix(in srgb,var(--accent-red) 15%,var(--bg-secondary));color:var(--accent-red)}button.milestone-reorder-btn.btn{font-size:.65rem;padding:.15rem .35rem;line-height:1;min-width:1.5rem;text-align:center}.milestones-completed-section{margin-top:.75rem}.milestones-completed-toggle{font-size:.8rem;color:var(--text-secondary);padding:.25rem 0}.milestone-card-summary{padding:.5rem .75rem;opacity:.7}.milestone-card-summary .milestone-info{display:flex;align-items:center;gap:.5rem}.milestone-complete-badge{font-size:.7rem;font-weight:700;padding:.1rem .4rem;border-radius:var(--radius-sm);background:color-mix(in srgb,var(--accent-green) 15%,var(--bg-secondary));color:var(--accent-green)}.mobile-tab-bar{display:none;position:fixed;bottom:0;left:0;right:0;z-index:1100;background:var(--bg-card);border-top:var(--border-width) solid var(--border-color);padding-bottom:env(safe-area-inset-bottom,0);height:calc(52px + env(safe-area-inset-bottom,0px))}.mobile-tab{flex:1;display:flex;align-items:center;justify-content:center;height:52px;background:0 0;border:none;color:var(--text-muted);font-size:.7rem;font-weight:700;font-family:var(--font-sans);text-transform:uppercase;letter-spacing:.05em;cursor:pointer;-webkit-tap-highlight-color:transparent;transition:color .15s ease}.mobile-tab.active{color:var(--accent-blue)}.mobile-tab:active{background:var(--bg-secondary)}.mobile-tab-create{font-size:1.4rem;font-weight:400;color:var(--accent-green);letter-spacing:0;text-transform:none}.mobile-more-popover{display:none;position:fixed;bottom:calc(52px + env(safe-area-inset-bottom,0px));right:0;background:var(--bg-card);border:var(--border-width) solid var(--border-color);border-radius:var(--radius-md);padding:.25rem 0;z-index:1101;min-width:160px;box-shadow:0 -2px 8px rgba(0,0,0,.1)}.mobile-more-popover.visible{display:block}.mobile-more-popover button{display:block;width:100%;padding:.75rem 1rem;background:0 0;border:none;text-align:left;font-size:var(--font-size-sm);font-weight:600;color:var(--text-primary);cursor:pointer}.mobile-more-popover button:active{background:var(--bg-secondary)}.action-sheet{position:fixed;inset:0;z-index:10001;display:flex;flex-direction:column;justify-content:flex-end}.action-sheet.hidden{display:none}.action-sheet-backdrop{position:absolute;inset:0;background:rgba(0,0,0,.4)}.action-sheet-container{position:relative;background:var(--bg-card);border-top:var(--border-width) solid var(--border-color);border-radius:var(--radius-lg) var(--radius-lg) 0 0;padding:.5rem 1rem calc(.5rem + env(safe-area-inset-bottom,0px));max-height:60vh;overflow-y:auto;animation:sheetSlideUp .25s ease-out}.action-sheet-handle{width:36px;height:4px;border-radius:2px;background:var(--text-muted);margin:0 auto .75rem;opacity:.4}.action-sheet-content button{display:flex;align-items:center;gap:.75rem;width:100%;padding:.875rem .5rem;background:0 0;border:none;border-bottom:1px solid var(--bg-secondary);font-size:var(--font-size-base);font-weight:600;color:var(--text-primary);text-align:left;cursor:pointer}.action-sheet-content button:last-child{border-bottom:none}.action-sheet-content button:active{background:var(--bg-secondary)}.action-sheet-content button.danger{color:var(--accent-red)}.action-sheet-cancel{display:block;width:100%;padding:.875rem;margin-top:.5rem;background:var(--bg-secondary);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-md);font-size:var(--font-size-base);font-weight:700;color:var(--text-primary);text-align:center;cursor:pointer}.action-sheet-cancel:active{background:var(--bg-tertiary)}.modal-drag-handle{display:none;width:36px;height:4px;border-radius:2px;background:var(--text-muted);margin:.5rem auto 0;opacity:.4}.mobile-sort-bar{display:none;gap:.5rem;padding:.5rem 0;align-items:center}.mobile-sort-bar select{flex:1;font-size:var(--font-size-sm)}.mobile-filter-toggle{display:none}.swipe-actions-container{position:relative;overflow:hidden}.swipe-actions-bg{position:absolute;top:0;bottom:0;display:flex;align-items:center;padding:0 1rem;font-weight:700;font-size:var(--font-size-sm);color:var(--text-on-accent)}.swipe-actions-bg.swipe-left{right:0;background:var(--accent-green)}.swipe-actions-bg.swipe-right{left:0;background:var(--accent-red)}.swipe-content{position:relative;background:var(--bg-card);transition:transform .15s ease}.pull-to-refresh-indicator{display:none;text-align:center;padding:.75rem;font-size:var(--font-size-sm);color:var(--text-muted);font-weight:600}.pull-to-refresh-indicator.visible{display:block}.event-date-group-header{display:none}.day-plan-sidebar-toggle{display:none}@keyframes sheetSlideUp{from{transform:translateY(100%)}to{transform:translateY(0)}}@keyframes sheetSlideDown{from{transform:translateY(0)}to{transform:translateY(100%)}}@keyframes dialFadeIn{from{opacity:0}to{opacity:1}}@media (max-width:768px){body{padding-top:env(safe-area-inset-top,0);padding-bottom:calc(52px + env(safe-area-inset-bottom,0px))}.mobile-tab-bar{display:flex}.tab-navigation{display:none!important}.app-header{display:none}.pill-nav{overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;padding:var(--space-1) var(--space-3)}.tab-group>.subview>.page-header{position:static}.pill-nav::-webkit-scrollbar{display:none}.main-content{padding:.75rem}.page-header{flex-wrap:wrap;gap:.5rem}.page-header .btn-primary{display:none}.page-title{display:none}.modal-overlay{align-items:flex-end}.modal-container{width:100%!important;max-width:100%!important;max-height:90vh;border-radius:var(--radius-lg) var(--radius-lg) 0 0;margin:0;border-bottom:none;padding-bottom:env(safe-area-inset-bottom,0)}.modal-container.modal-large{max-width:100%!important;width:100%!important;max-height:95vh;border-radius:var(--radius-lg) var(--radius-lg) 0 0}.modal-drag-handle{display:block}.modal-header{padding:.75rem 1rem}.modal-content{padding:1rem}@keyframes modalSlideIn{from{transform:translateY(100%)}to{transform:translateY(0)}}@keyframes modalSlideOut{from{transform:translateY(0)}to{transform:translateY(100%)}}.toast,.toast-undo{bottom:calc(env(safe-area-inset-bottom,0px) + 4.5rem)!important;left:1rem!important;right:1rem!important;max-width:none!important}.task-table{border:none;box-shadow:none;background:0 0}.task-header-row{display:none!important}.task-row{display:flex!important;flex-direction:column;gap:.25rem;padding:.75rem 1rem;margin-bottom:.5rem;background:var(--bg-card);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-md);border-left:4px solid var(--text-muted)}.task-row.task-pending{border-left-color:var(--text-muted)}.task-row .task-cell.priority-h~.task-cell:first-child,.task-row:has(.priority-h){border-left-color:var(--accent-red)}.task-row:has(.priority-m){border-left-color:var(--accent-yellow)}.task-row:has(.priority-l){border-left-color:var(--text-muted)}.task-row .task-cell{display:flex!important;overflow:visible;padding:0}.task-cell.task-description{font-weight:600;font-size:var(--font-size-base)}.task-cell.task-due,.task-cell.task-project{font-size:var(--font-size-sm);color:var(--text-secondary)}.task-row .task-cell.task-project::before{content:none}.task-cell.task-progress,.task-cell.task-recurrence,.task-row .task-cell:nth-child(3){display:none!important}.task-cell.task-project{order:2}.task-cell.task-due{order:3}.task-cell.task-description{order:1}.task-cell.task-actions-cell{order:4;justify-content:flex-end}.task-cell.task-progress:has(.progress-bar-container){display:flex!important;order:5}.task-actions-cell .bulk-checkbox{display:none}.mobile-sort-bar{display:flex}.mobile-filter-toggle{display:inline-flex;align-items:center;gap:.25rem;padding:.5rem .75rem;background:var(--bg-card);border:var(--border-width-sm) solid var(--border-color);border-radius:var(--radius-sm);font-size:var(--font-size-sm);font-weight:600;cursor:pointer}.filter-bar{display:none!important}.filter-bar.mobile-visible{display:flex!important;flex-direction:column;position:fixed;bottom:0;left:0;right:0;background:var(--bg-card);border-top:var(--border-width) solid var(--border-color);border-radius:var(--radius-lg) var(--radius-lg) 0 0;padding:1rem;padding-bottom:calc(1rem + env(safe-area-inset-bottom,0px));z-index:1050;box-shadow:0 -4px 12px rgba(0,0,0,.1)}.event-header-row{display:none!important}.event-row-virtual{display:flex!important;flex-direction:column;gap:.125rem;padding:.75rem 1rem;border-bottom:1px solid var(--bg-secondary)}.event-cell-date{font-weight:700;font-size:var(--font-size-sm);color:var(--text-secondary)}.event-cell-time{font-size:var(--font-size-sm);color:var(--text-muted)}.event-cell-title{font-weight:600;font-size:var(--font-size-base)}.event-cell-location{font-size:var(--font-size-sm);color:var(--text-secondary)}.event-date-group-header{display:flex;position:sticky;top:0;z-index:5;padding:.5rem 1rem;background:var(--bg-secondary);font-weight:700;font-size:var(--font-size-sm);text-transform:uppercase;letter-spacing:.05em;color:var(--text-primary);border-bottom:var(--border-width-sm) solid var(--border-color)}.email-item{padding:.625rem .75rem}.email-from{font-size:var(--font-size-sm)}.email-subject{font-size:var(--font-size-base)}.email-preview{display:none}.email-date{font-size:var(--font-size-xs)}.email-item .bulk-checkbox{display:none}.day-plan-content{flex-direction:column}.day-plan-sidebar{width:100%;max-height:none;border-top:var(--border-width-sm) solid var(--border-color);order:2}.day-plan-sidebar.collapsed .sidebar-task-list{display:none}.day-plan-sidebar-toggle{display:flex;align-items:center;justify-content:space-between;width:100%;padding:.625rem .75rem;background:var(--bg-secondary);border:none;border-bottom:1px solid var(--border-color);font-size:var(--font-size-sm);font-weight:700;cursor:pointer;color:var(--text-primary)}.day-plan-main{order:1}.day-plan-nav{flex-wrap:wrap;gap:.25rem}.weekly-review-content{padding:0}.monthly-review-content{padding:0}.month-reflection-textarea,.prompt-input{resize:none;overflow:hidden}.monthly-review-nav{flex-wrap:wrap;gap:.25rem}.monthly-review-month-display{font-size:1rem}.day-summary-sheet{padding:.5rem 0}.day-summary-date{font-size:1rem;font-weight:700;margin-bottom:.75rem;color:var(--text-primary)}.day-summary-stats{display:flex;gap:.5rem;margin-bottom:1rem}.day-summary-chip{padding:.25rem .75rem;background:var(--bg-secondary);border-radius:var(--radius-sm);font-size:var(--font-size-sm);font-weight:600;color:var(--text-secondary)}.day-summary-list{list-style:none;padding:0;margin:0 0 1rem 0}.day-summary-item{padding:.5rem 0;border-bottom:1px solid var(--bg-secondary);font-size:var(--font-size-sm);color:var(--text-primary)}.day-summary-time{font-weight:600;color:var(--text-secondary);margin-right:.5rem}.day-summary-more{color:var(--text-muted);font-style:italic}.day-summary-empty{color:var(--text-muted);font-size:var(--font-size-sm);margin:.5rem 0 1rem}.day-summary-go-btn{width:100%;margin-top:.5rem}.bulk-actions-bar{position:fixed;bottom:0;left:0;right:0;z-index:1050;border-radius:var(--radius-lg) var(--radius-lg) 0 0;padding-bottom:calc(.75rem + env(safe-area-inset-bottom,0px));box-shadow:0 -4px 12px rgba(0,0,0,.15)}.pagination-controls{padding:.5rem}.pagination-controls .btn{padding:.5rem .75rem;font-size:var(--font-size-sm)}}@media (hover:none){.task-row:hover{background-color:transparent}.task-row-clickable:hover{background:0 0}.event-row-virtual:hover{background-color:transparent}.email-item:hover{background-color:transparent}.card:hover{background-color:var(--bg-card);transform:none;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.btn:hover{background:var(--bg-card)}.btn-primary:hover{background-color:var(--accent-blue)}.btn-danger:hover{background-color:var(--accent-red)}.dashboard-item:hover{background:var(--bg-card);transform:none;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.kanban-card:hover{background:var(--bg-card);transform:none;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.saved-view-item:hover{background:var(--bg-card);color:var(--text-primary);transform:none;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color)}.context-menu-item:hover{background:0 0;color:var(--text-primary)}.modal-close:hover{background:var(--bg-card);color:var(--text-primary)}.month-heatmap-cell:hover{background:0 0;transform:none}}.view-toggle{display:flex;gap:0;margin-left:auto}.view-toggle-btn{padding:.35rem .75rem;border:var(--border-width-sm) solid var(--border-color);background:var(--bg-secondary);font-family:var(--font-body);font-size:var(--font-size-md);cursor:pointer;transition:background var(--transition-fast),box-shadow var(--transition-fast)}.view-toggle-btn.active{background:var(--bg-card);font-weight:600}.view-toggle-btn:first-child{border-radius:var(--radius-xs) 0 0 var(--radius-xs)}.view-toggle-btn:last-child{border-radius:0 var(--radius-xs) var(--radius-xs) 0;border-left:none}.kanban-board{display:grid;grid-template-columns:repeat(3,1fr);gap:1rem;padding:.5rem 0;min-height:400px}.kanban-column{background:var(--bg-card);border:var(--border-width) solid var(--border-color);display:flex;flex-direction:column;min-height:300px;max-height:calc(100vh - 200px)}.kanban-column-header{padding:.75rem 1rem;border-bottom:2px solid var(--border-color);font-family:var(--font-heading);font-weight:700;display:flex;justify-content:space-between;align-items:center}.kanban-column-count{font-family:var(--font-body);font-size:var(--font-size-sm);color:var(--text-secondary)}.kanban-column-body{flex:1;overflow-y:auto;padding:.5rem;display:flex;flex-direction:column;gap:.5rem}.kanban-column.drag-over{background-color:var(--bg-tertiary)}.kanban-empty{text-align:center;padding:2rem 1rem;color:var(--text-secondary);font-size:var(--font-size-sm)}.kanban-card{padding:.75rem;background:var(--bg-card);border:var(--border-width-sm) solid var(--border-color);cursor:grab;box-shadow:var(--shadow-offset) var(--shadow-offset) 0 var(--border-color);transition:transform .15s ease,box-shadow .15s ease,background-color .15s ease;border-left:4px solid transparent}.kanban-card:hover{background:var(--bg-secondary);transform:translate(-2px,-2px);box-shadow:calc(var(--shadow-offset) + 2px) calc(var(--shadow-offset) + 2px) 0 var(--border-color)}.kanban-card.dragging{opacity:.5;cursor:grabbing}.kanban-card.priority-high{border-left-color:var(--accent-red)}.kanban-card.priority-medium{border-left-color:var(--accent-yellow)}.kanban-card.priority-low{border-left-color:var(--accent-green)}.kanban-card-title{font-weight:600;margin-bottom:.25rem}.kanban-card-meta{font-size:var(--font-size-sm);color:var(--text-secondary);display:flex;gap:.5rem;flex-wrap:wrap}.kanban-card-due.overdue{color:var(--accent-red);font-weight:600}.progress-bar-mini{height:3px;background:var(--bg-tertiary);border-radius:2px;margin-top:.5rem}.progress-bar-mini .progress-fill{height:100%;background:var(--accent-green);border-radius:2px}@media (max-width:768px){.kanban-board{grid-template-columns:1fr}.kanban-column{max-height:none}} | |
| 1 | < | \ No newline at end of file |
| @@ -406,24 +406,26 @@ | |||
| 406 | 406 | <!-- Content populated dynamically by JS --> | |
| 407 | 407 | </div> | |
| 408 | 408 | ||
| 409 | - | <!-- Mobile Navigation Dot (hidden on desktop) --> | |
| 410 | - | <div id="nav-dot" class="nav-dot" role="navigation" aria-label="Mobile navigation"> | |
| 411 | - | <span class="nav-dot-icon" id="nav-dot-icon">GO</span> | |
| 412 | - | </div> | |
| 413 | - | <div id="nav-dot-status" class="nav-dot-status"></div> | |
| 414 | - | <div id="nav-dial" class="nav-dial hidden" role="menu" aria-label="Navigation menu"> | |
| 415 | - | <button class="nav-dial-item nav-dial-center" data-action="create" role="menuitem" aria-label="Create new item">+</button> | |
| 416 | - | <button class="nav-dial-item" data-view="work" role="menuitem" aria-label="Work"> | |
| 417 | - | <span class="nav-dial-label">Work</span> | |
| 409 | + | <!-- Mobile Bottom Tab Bar (hidden on desktop) --> | |
| 410 | + | <nav id="mobile-tab-bar" class="mobile-tab-bar" role="tablist" aria-label="Mobile navigation"> | |
| 411 | + | <button class="mobile-tab active" data-view="work" role="tab" aria-selected="true"> | |
| 412 | + | <span class="mobile-tab-label">Work</span> | |
| 413 | + | </button> | |
| 414 | + | <button class="mobile-tab" data-view="time" role="tab" aria-selected="false"> | |
| 415 | + | <span class="mobile-tab-label">Time</span> | |
| 418 | 416 | </button> | |
| 419 | - | <button class="nav-dial-item" data-view="time" role="menuitem" aria-label="Time"> | |
| 420 | - | <span class="nav-dial-label">Time</span> | |
| 417 | + | <button class="mobile-tab" data-view="messages" role="tab" aria-selected="false"> | |
| 418 | + | <span class="mobile-tab-label">Messages</span> | |
| 421 | 419 | </button> | |
| 422 | - | <button class="nav-dial-item" data-view="messages" role="menuitem" aria-label="Messages"> | |
| 423 | - | <span class="nav-dial-label">Messages</span> | |
| 420 | + | <button class="mobile-tab mobile-tab-create" id="mobile-create-btn" aria-label="Create new item">+</button> | |
| 421 | + | <button class="mobile-tab mobile-tab-more" id="mobile-more-btn" aria-label="More options"> | |
| 422 | + | <span class="mobile-tab-label">More</span> | |
| 424 | 423 | </button> | |
| 424 | + | </nav> | |
| 425 | + | <div id="mobile-more-popover" class="mobile-more-popover"> | |
| 426 | + | <button onclick="GoingsOn.settings.open(); GoingsOn.navigation.closeMorePopover();">Settings</button> | |
| 427 | + | <button onclick="GoingsOn.keyboard.showShortcuts(); GoingsOn.navigation.closeMorePopover();">Shortcuts</button> | |
| 425 | 428 | </div> | |
| 426 | - | <div id="nav-dial-backdrop" class="nav-dial-backdrop hidden"></div> | |
| 427 | 429 | ||
| 428 | 430 | <!-- Action Bottom Sheet (mobile context menus) --> | |
| 429 | 431 | <div id="action-sheet" class="action-sheet hidden" role="dialog" aria-modal="true" aria-label="Actions"> |
| @@ -265,7 +265,7 @@ | |||
| 265 | 265 | // ============ Helpers ============ | |
| 266 | 266 | ||
| 267 | 267 | function parseTags(tagString) { | |
| 268 | - | return tagString ? tagString.split(',').map(t => t.trim()).filter(t => t) : []; | |
| 268 | + | return GoingsOn.utils.normalizeTags(tagString); | |
| 269 | 269 | } | |
| 270 | 270 | ||
| 271 | 271 | function getAllTags(contacts) { | |
| @@ -475,7 +475,7 @@ | |||
| 475 | 475 | // ============ Filtering ============ | |
| 476 | 476 | ||
| 477 | 477 | function filterBySearch(query) { | |
| 478 | - | GoingsOn.state.set('contactsSearchQuery', query); | |
| 478 | + | GoingsOn.state.set('contactsSearchQuery', query.trim()); | |
| 479 | 479 | load(); | |
| 480 | 480 | } | |
| 481 | 481 |
| @@ -40,20 +40,24 @@ | |||
| 40 | 40 | }, | |
| 41 | 41 | { | |
| 42 | 42 | name: 'start_time', | |
| 43 | - | type: 'datetime-local', | |
| 43 | + | type: 'text', | |
| 44 | 44 | label: 'Start Date & Time', | |
| 45 | + | placeholder: 'tomorrow 3pm, friday 10:00, 2026-12-25...', | |
| 45 | 46 | required: true, | |
| 46 | 47 | value: event?.start_time | |
| 47 | 48 | ? new Date(event.start_time).toISOString().slice(0, 16) | |
| 48 | 49 | : localISOTime, | |
| 50 | + | transform: (v) => GoingsOn.utils.parseNaturalDate(v) || v, | |
| 49 | 51 | }, | |
| 50 | 52 | { | |
| 51 | 53 | name: 'end_time', | |
| 52 | - | type: 'datetime-local', | |
| 54 | + | type: 'text', | |
| 53 | 55 | label: 'End Time (optional)', | |
| 56 | + | placeholder: 'tomorrow 5pm, friday 12:00...', | |
| 54 | 57 | value: event?.end_time | |
| 55 | 58 | ? new Date(event.end_time).toISOString().slice(0, 16) | |
| 56 | 59 | : '', | |
| 60 | + | transform: (v) => GoingsOn.utils.parseNaturalDate(v) || v, | |
| 57 | 61 | validate: (v, data) => { | |
| 58 | 62 | if (v && data.start_time && new Date(v) < new Date(data.start_time)) { | |
| 59 | 63 | return 'End time must be after start time'; | |
| @@ -444,32 +448,6 @@ | |||
| 444 | 448 | dot.setAttribute('aria-label', label); | |
| 445 | 449 | } | |
| 446 | 450 | ||
| 447 | - | // Mobile: dot below nav dot (when dial closed) | |
| 448 | - | const navDotStatus = document.getElementById('nav-dot-status'); | |
| 449 | - | if (navDotStatus) { | |
| 450 | - | let mdot = navDotStatus.querySelector('.tab-status-dot'); | |
| 451 | - | if (!mdot) { | |
| 452 | - | mdot = document.createElement('span'); | |
| 453 | - | mdot.className = 'tab-status-dot'; | |
| 454 | - | navDotStatus.appendChild(mdot); | |
| 455 | - | } | |
| 456 | - | mdot.className = 'tab-status-dot status-' + status; | |
| 457 | - | mdot.setAttribute('aria-label', label); | |
| 458 | - | } | |
| 459 | - | ||
| 460 | - | // Mobile: dot on the events dial petal (when dial open) | |
| 461 | - | const dialItem = document.querySelector('.nav-dial-item[data-view="events"]'); | |
| 462 | - | if (dialItem) { | |
| 463 | - | let ddot = dialItem.querySelector('.tab-status-dot'); | |
| 464 | - | if (!ddot) { | |
| 465 | - | ddot = document.createElement('span'); | |
| 466 | - | ddot.className = 'tab-status-dot'; | |
| 467 | - | ddot.style.cssText = 'position:absolute;top:-3px;right:-3px;width:10px;height:10px;margin:0;border:none;'; | |
| 468 | - | dialItem.appendChild(ddot); | |
| 469 | - | } | |
| 470 | - | ddot.className = 'tab-status-dot status-' + status; | |
| 471 | - | ddot.setAttribute('aria-label', label); | |
| 472 | - | } | |
| 473 | 451 | } | |
| 474 | 452 | ||
| 475 | 453 | function startEventStatusPolling() { |
| @@ -149,6 +149,11 @@ function openFormModal(config) { | |||
| 149 | 149 | } else { | |
| 150 | 150 | formData[field.name] = el.value; | |
| 151 | 151 | } | |
| 152 | + | ||
| 153 | + | // Apply field transform if defined | |
| 154 | + | if (field.transform && formData[field.name]) { | |
| 155 | + | formData[field.name] = field.transform(formData[field.name]); | |
| 156 | + | } | |
| 152 | 157 | } | |
| 153 | 158 | ||
| 154 | 159 | // Validate all fields |
| @@ -1,6 +1,6 @@ | |||
| 1 | 1 | /** | |
| 2 | 2 | * GoingsOn - Navigation Module | |
| 3 | - | * View switching, window title management, tab navigation, mobile nav dot | |
| 3 | + | * View switching, window title management, tab navigation, mobile tab bar | |
| 4 | 4 | */ | |
| 5 | 5 | ||
| 6 | 6 | (function() { | |
| @@ -26,85 +26,20 @@ const TAB_DEFAULTS = { | |||
| 26 | 26 | 'messages': 'emails', | |
| 27 | 27 | }; | |
| 28 | 28 | ||
| 29 | - | // ============ Sub-View Expansion ============ | |
| 30 | - | ||
| 31 | - | const SUB_VIEW_MAP = { | |
| 32 | - | 'work': ['tasks', 'projects'], | |
| 33 | - | 'time': ['day-plan', 'weekly-review', 'monthly-review'], | |
| 34 | - | 'messages': ['emails', 'contacts'], | |
| 29 | + | const VIEW_LABELS = { | |
| 30 | + | 'work': 'Work', | |
| 31 | + | 'time': 'Time', | |
| 32 | + | 'messages': 'Messages', | |
| 33 | + | 'tasks': 'Tasks', | |
| 34 | + | 'projects': 'Projects', | |
| 35 | + | 'emails': 'Email', | |
| 36 | + | 'contacts': 'Contacts', | |
| 37 | + | 'day-plan': 'Day', | |
| 38 | + | 'weekly-review': 'Week', | |
| 39 | + | 'monthly-review': 'Month', | |
| 40 | + | 'settings': 'Settings', | |
| 35 | 41 | }; | |
| 36 | 42 | ||
| 37 | - | let expandedTab = null; | |
| 38 | - | ||
| 39 | - | function expandSubViews(tabName) { | |
| 40 | - | const subViews = SUB_VIEW_MAP[tabName]; | |
| 41 | - | if (!subViews) return; | |
| 42 | - | ||
| 43 | - | const dial = document.getElementById('nav-dial'); | |
| 44 | - | if (!dial) return; | |
| 45 | - | ||
| 46 | - | expandedTab = tabName; | |
| 47 | - | ||
| 48 | - | // Remove existing non-center items | |
| 49 | - | dial.querySelectorAll('.nav-dial-item:not(.nav-dial-center)').forEach(el => el.remove()); | |
| 50 | - | ||
| 51 | - | // Create sub-view petals | |
| 52 | - | const currentView = GoingsOn.state.currentView; | |
| 53 | - | for (const sv of subViews) { | |
| 54 | - | const btn = document.createElement('button'); | |
| 55 | - | btn.className = 'nav-dial-item nav-dial-subitem'; | |
| 56 | - | btn.dataset.view = sv; | |
| 57 | - | btn.setAttribute('role', 'menuitem'); | |
| 58 | - | btn.setAttribute('aria-label', VIEW_LABELS[sv] || sv); | |
| 59 | - | if (sv === currentView) btn.classList.add('active'); | |
| 60 | - | ||
| 61 | - | const label = document.createElement('span'); | |
| 62 | - | label.className = 'nav-dial-label'; | |
| 63 | - | label.textContent = VIEW_LABELS[sv] || sv; | |
| 64 | - | btn.appendChild(label); | |
| 65 | - | dial.appendChild(btn); | |
| 66 | - | } | |
| 67 | - | ||
| 68 | - | // Re-position | |
| 69 | - | const dot = document.getElementById('nav-dot'); | |
| 70 | - | if (dot) positionDialItems(dot, dial); | |
| 71 | - | } | |
| 72 | - | ||
| 73 | - | function restoreDialPetals() { | |
| 74 | - | if (!expandedTab) return; | |
| 75 | - | expandedTab = null; | |
| 76 | - | ||
| 77 | - | const dial = document.getElementById('nav-dial'); | |
| 78 | - | if (!dial) return; | |
| 79 | - | ||
| 80 | - | // Remove sub-view items | |
| 81 | - | dial.querySelectorAll('.nav-dial-item:not(.nav-dial-center)').forEach(el => el.remove()); | |
| 82 | - | ||
| 83 | - | // Recreate tab-level petals | |
| 84 | - | const tabs = ['work', 'time', 'messages']; | |
| 85 | - | const currentView = GoingsOn.state.currentView; | |
| 86 | - | const activeParent = TAB_GROUPS[currentView] || currentView; | |
| 87 | - | ||
| 88 | - | for (const tab of tabs) { | |
| 89 | - | const btn = document.createElement('button'); | |
| 90 | - | btn.className = 'nav-dial-item'; | |
| 91 | - | btn.dataset.view = tab; | |
| 92 | - | btn.setAttribute('role', 'menuitem'); | |
| 93 | - | btn.setAttribute('aria-label', VIEW_LABELS[tab] || tab); | |
| 94 | - | if (tab === activeParent) btn.classList.add('active'); | |
| 95 | - | ||
| 96 | - | const label = document.createElement('span'); | |
| 97 | - | label.className = 'nav-dial-label'; | |
| 98 | - | label.textContent = VIEW_LABELS[tab] || tab; | |
| 99 | - | btn.appendChild(label); | |
| 100 | - | dial.appendChild(btn); | |
| 101 | - | } | |
| 102 | - | ||
| 103 | - | // Re-position | |
| 104 | - | const dot = document.getElementById('nav-dot'); | |
| 105 | - | if (dot) positionDialItems(dot, dial); | |
| 106 | - | } | |
| 107 | - | ||
| 108 | 43 | // ============ View Navigation ============ | |
| 109 | 44 | ||
| 110 | 45 | // Tab click handlers | |
| @@ -142,7 +77,6 @@ document.addEventListener('keydown', (e) => { | |||
| 142 | 77 | function switchView(view) { | |
| 143 | 78 | // Handle settings specially (not a view panel) | |
| 144 | 79 | if (view === 'settings') { | |
| 145 | - | closeDial(); | |
| 146 | 80 | GoingsOn.settings?.open(); | |
| 147 | 81 | return; | |
| 148 | 82 | } | |
| @@ -157,6 +91,11 @@ function switchView(view) { | |||
| 157 | 91 | ||
| 158 | 92 | GoingsOn.state.set('currentView', view); | |
| 159 | 93 | ||
| 94 | + | // Track view switch counts | |
| 95 | + | const c = GoingsOn.state.viewSwitchCounts || {}; | |
| 96 | + | c[view] = (c[view] || 0) + 1; | |
| 97 | + | GoingsOn.state.viewSwitchCounts = c; | |
| 98 | + | ||
| 160 | 99 | // Determine parent tab | |
| 161 | 100 | const parentTab = TAB_GROUPS[view]; | |
| 162 | 101 | ||
| @@ -208,14 +147,11 @@ function switchView(view) { | |||
| 208 | 147 | // Load data for view | |
| 209 | 148 | loadViewData(view); | |
| 210 | 149 | ||
| 211 | - | // Update nav dot icon on mobile | |
| 212 | - | updateNavDotIcon(view); | |
| 213 | - | ||
| 214 | 150 | // Update mobile header view title | |
| 215 | 151 | updateMobileViewTitle(view); | |
| 216 | 152 | ||
| 217 | - | // Close dial if open | |
| 218 | - | closeDial(); | |
| 153 | + | // Update mobile tab bar active state | |
| 154 | + | updateMobileTabBar(view); | |
| 219 | 155 | } | |
| 220 | 156 | ||
| 221 | 157 | /** | |
| @@ -282,34 +218,7 @@ function setCurrentView(view) { | |||
| 282 | 218 | GoingsOn.state.set('currentView', view); | |
| 283 | 219 | } | |
| 284 | 220 | ||
| 285 | - | // ============ Mobile Navigation Dot & Radial Dial ============ | |
| 286 | - | ||
| 287 | - | const VIEW_LABELS = { | |
| 288 | - | 'work': 'Work', | |
| 289 | - | 'time': 'Time', | |
| 290 | - | 'messages': 'Messages', | |
| 291 | - | 'tasks': 'Tasks', | |
| 292 | - | 'projects': 'Projects', | |
| 293 | - | 'emails': 'Email', | |
| 294 | - | 'contacts': 'Contacts', | |
| 295 | - | 'day-plan': 'Day', | |
| 296 | - | 'weekly-review': 'Week', | |
| 297 | - | 'monthly-review': 'Month', | |
| 298 | - | 'settings': 'Settings', | |
| 299 | - | }; | |
| 300 | - | ||
| 301 | - | let dialOpen = false; | |
| 302 | - | let dotPosition = { x: null, y: null }; // null = use CSS default | |
| 303 | - | let handledByTouch = false; // Prevent double-fire from touch + synthesized click | |
| 304 | - | ||
| 305 | - | /** | |
| 306 | - | * Update the nav dot icon to reflect the current view. | |
| 307 | - | */ | |
| 308 | - | function updateNavDotIcon(view) { | |
| 309 | - | const iconEl = document.getElementById('nav-dot-icon'); | |
| 310 | - | if (!iconEl) return; | |
| 311 | - | iconEl.textContent = VIEW_LABELS[view] || 'GO'; | |
| 312 | - | } | |
| 221 | + | // ============ Mobile View Title ============ | |
| 313 | 222 | ||
| 314 | 223 | function updateMobileViewTitle(view) { | |
| 315 | 224 | const el = document.getElementById('mobile-view-title'); | |
| @@ -317,160 +226,23 @@ function updateMobileViewTitle(view) { | |||
| 317 | 226 | el.textContent = VIEW_LABELS[view] || ''; | |
| 318 | 227 | } | |
| 319 | 228 | ||
| 320 | - | /** | |
| 321 | - | * Toggle the radial dial open/closed. | |
| 322 | - | */ | |
| 323 | - | function toggleDial() { | |
| 324 | - | if (dialOpen) { | |
| 325 | - | closeDial(); | |
| 326 | - | } else { | |
| 327 | - | openDial(); | |
| 328 | - | } | |
| 329 | - | } | |
| 229 | + | // ============ Mobile Tab Bar ============ | |
| 330 | 230 | ||
| 331 | - | function openDial() { | |
| 332 | - | const dot = document.getElementById('nav-dot'); | |
| 333 | - | const dial = document.getElementById('nav-dial'); | |
| 334 | - | const backdrop = document.getElementById('nav-dial-backdrop'); | |
| 335 | - | if (!dot || !dial) return; | |
| 336 | - | ||
| 337 | - | dialOpen = true; | |
| 338 | - | dot.classList.add('dial-open'); | |
| 339 | - | dial.classList.remove('hidden'); | |
| 340 | - | dial.classList.add('visible'); | |
| 341 | - | backdrop.classList.remove('hidden'); | |
| 342 | - | backdrop.classList.add('visible'); | |
| 343 | - | const navDotStatus = document.getElementById('nav-dot-status'); | |
| 344 | - | if (navDotStatus) navDotStatus.classList.add('dial-open'); | |
| 345 | - | ||
| 346 | - | // Position dial items radially around the dot | |
| 347 | - | positionDialItems(dot, dial); | |
| 348 | - | ||
| 349 | - | // Mark active tab in dial | |
| 350 | - | const currentView = GoingsOn.state.currentView; | |
| 351 | - | const activeParent = TAB_GROUPS[currentView] || currentView; | |
| 352 | - | dial.querySelectorAll('.nav-dial-item').forEach(item => { | |
| 353 | - | item.classList.toggle('active', item.dataset.view === activeParent); | |
| 231 | + | function updateMobileTabBar(view) { | |
| 232 | + | const bar = document.getElementById('mobile-tab-bar'); | |
| 233 | + | if (!bar) return; | |
| 234 | + | const parentTab = TAB_GROUPS[view] || view; | |
| 235 | + | bar.querySelectorAll('.mobile-tab[data-view]').forEach(t => { | |
| 236 | + | t.classList.toggle('active', t.dataset.view === parentTab); | |
| 237 | + | t.setAttribute('aria-selected', t.dataset.view === parentTab ? 'true' : 'false'); | |
| 354 | 238 | }); | |
| 355 | 239 | } | |
| 356 | 240 | ||
| 357 | - | function closeDial() { | |
| 358 | - | const dot = document.getElementById('nav-dot'); | |
| 359 | - | const dial = document.getElementById('nav-dial'); | |
| 360 | - | const backdrop = document.getElementById('nav-dial-backdrop'); | |
| 361 | - | if (!dial) return; | |
| 362 | - | ||
| 363 | - | // Restore tab-level petals if sub-views were expanded | |
| 364 | - | if (expandedTab) restoreDialPetals(); | |
| 365 | - | ||
| 366 | - | dialOpen = false; | |
| 367 | - | if (dot) dot.classList.remove('dial-open'); | |
| 368 | - | dial.classList.remove('visible'); | |
| 369 | - | dial.classList.add('hidden'); | |
| 370 | - | if (backdrop) { | |
| 371 | - | backdrop.classList.remove('visible'); | |
| 372 | - | backdrop.classList.add('hidden'); | |
| 373 | - | } | |
| 374 | - | const navDotStatus = document.getElementById('nav-dot-status'); | |
| 375 | - | if (navDotStatus) navDotStatus.classList.remove('dial-open'); | |
| 376 | - | } | |
| 377 | - | ||
| 378 | - | /** | |
| 379 | - | * Position dial items as rotated petal spokes around the nav dot. | |
| 380 | - | * Automatically computes the minimum radius so no petals overlap. | |
| 381 | - | * Arcs are ~90° based on which corner the dot is nearest. | |
| 382 | - | */ | |
| 383 | - | function positionDialItems(dot, dial) { | |
| 384 | - | const dotRect = dot.getBoundingClientRect(); | |
| 385 | - | const centerX = dotRect.left + dotRect.width / 2; | |
| 386 | - | const centerY = dotRect.top + dotRect.height / 2; | |
| 387 | - | ||
| 388 | - | // Place dial at dot's center | |
| 389 | - | dial.style.left = `${centerX}px`; | |
| 390 | - | dial.style.top = `${centerY}px`; | |
| 391 | - | ||
| 392 | - | const items = dial.querySelectorAll('.nav-dial-item:not(.nav-dial-center)'); | |
| 393 | - | const centerItem = dial.querySelector('.nav-dial-center'); | |
| 394 | - | const count = items.length; | |
| 395 | - | if (count === 0) return; | |
| 396 | - | ||
| 397 | - | // Petal dimensions (must match CSS) | |
| 398 | - | const petalW = 72; | |
| 399 | - | const petalH = 28; | |
| 400 | - | const gap = 4; | |
| 401 | - | ||
| 402 | - | // 90° arc pointing away from the nearest corner | |
| 403 | - | const isRight = centerX > window.innerWidth / 2; | |
| 404 | - | const isBottom = centerY > window.innerHeight / 2; | |
| 405 | - | ||
| 406 | - | let startAngle, endAngle; | |
| 407 | - | if (isRight && isBottom) { | |
| 408 | - | // Bottom-right: fan into upper-left quadrant | |
| 409 | - | startAngle = 180; endAngle = 270; | |
| 410 | - | } else if (!isRight && isBottom) { | |
| 411 | - | // Bottom-left: fan into upper-right quadrant | |
| 412 | - | startAngle = 270; endAngle = 360; | |
| 413 | - | } else if (isRight && !isBottom) { | |
| 414 | - | // Top-right: fan into lower-left quadrant | |
| 415 | - | startAngle = 90; endAngle = 180; | |
| 416 | - | } else { | |
| 417 | - | // Top-left: fan into lower-right quadrant | |
| 418 | - | startAngle = 0; endAngle = 90; | |
| 419 | - | } | |
| 420 | - | ||
| 421 | - | const arcSpanRad = (endAngle - startAngle) * (Math.PI / 180); | |
| 422 | - | const angleStepRad = arcSpanRad / (count - 1 || 1); | |
| 423 | - | ||
| 424 | - | // Minimum radius so adjacent petals don't collide. | |
| 425 | - | // At the spoke tip, adjacent petal centers are separated by chord = 2r·sin(step/2). | |
| 426 | - | // The petal's cross-section at that point is petalH, so chord >= petalH + gap. | |
| 427 | - | const minChord = petalH + gap; | |
| 428 | - | const halfStep = angleStepRad / 2; | |
| 429 | - | const minRadius = halfStep > 0 ? minChord / (2 * Math.sin(halfStep)) : 100; | |
| 430 | - | // Also ensure petals clear the dot | |
| 431 | - | const radius = Math.max(minRadius, (petalW / 2) + (dotRect.width / 2) + gap); | |
| 432 | - | ||
| 433 | - | const angleStepDeg = (endAngle - startAngle) / (count - 1 || 1); | |
| 434 | - | ||
| 435 | - | items.forEach((item, i) => { | |
| 436 | - | const angleDeg = startAngle + angleStepDeg * i; | |
| 437 | - | const angleRad = angleDeg * (Math.PI / 180); | |
| 438 | - | const x = Math.cos(angleRad) * radius; | |
| 439 | - | const y = Math.sin(angleRad) * radius; | |
| 440 | - | ||
| 441 | - | // Position petal center at (x, y) relative to dial origin | |
| 442 | - | item.style.left = `${x - petalW / 2}px`; | |
| 443 | - | item.style.top = `${y - petalH / 2}px`; | |
| 444 | - | ||
| 445 | - | // Align petal along the spoke. Flip 180° if text would be upside-down | |
| 446 | - | // (i.e. rotation between 90° and 270° makes letters inverted). | |
| 447 | - | let rot = angleDeg; | |
| 448 | - | const n = ((rot % 360) + 360) % 360; | |
| 449 | - | if (n > 90 && n <= 270) { | |
| 450 | - | rot += 180; | |
| 451 | - | } | |
| 452 | - | item.style.transform = `rotate(${rot}deg)`; | |
| 453 | - | ||
| 454 | - | // Reverse z-order: last angular item underneath, first on top | |
| 455 | - | item.style.zIndex = count - i; | |
| 456 | - | item.style.transitionDelay = `${i * 30}ms`; | |
| 457 | - | }); | |
| 458 | - | ||
| 459 | - | // Center "+" button at the dot position | |
| 460 | - | if (centerItem) { | |
| 461 | - | const centerSize = 44; | |
| 462 | - | centerItem.style.left = `${-(centerSize / 2)}px`; | |
| 463 | - | centerItem.style.top = `${-(centerSize / 2)}px`; | |
| 464 | - | centerItem.style.transform = 'none'; | |
| 465 | - | } | |
| 466 | - | } | |
| 467 | - | ||
| 468 | 241 | /** | |
| 469 | 242 | * Create a new item for the current view. | |
| 470 | 243 | */ | |
| 471 | 244 | function newItemForCurrentView() { | |
| 472 | 245 | const view = GoingsOn.state.currentView; | |
| 473 | - | closeDial(); | |
| 474 | 246 | ||
| 475 | 247 | switch (view) { | |
| 476 | 248 | case 'projects': GoingsOn.projects.openNew?.(); break; | |
| @@ -483,144 +255,67 @@ function newItemForCurrentView() { | |||
| 483 | 255 | } | |
| 484 | 256 | } | |
| 485 | 257 | ||
| 486 | - | // ============ Nav Dot Drag to Reposition ============ | |
| 487 | - | ||
| 488 | - | function initNavDotDrag() { | |
| 489 | - | const dot = document.getElementById('nav-dot'); | |
| 490 | - | if (!dot) return; | |
| 491 | - | ||
| 492 | - | let isDragging = false; | |
| 493 | - | let hasMoved = false; | |
| 494 | - | let startX, startY, origLeft, origTop; | |
| 495 | - | ||
| 496 | - | dot.addEventListener('touchstart', (e) => { | |
| 497 | - | if (dialOpen) return; | |
| 498 | - | const touch = e.touches[0]; | |
| 499 | - | startX = touch.clientX; | |
| 500 | - | startY = touch.clientY; | |
| 501 | - | const rect = dot.getBoundingClientRect(); | |
| 502 | - | origLeft = rect.left; | |
| 503 | - | origTop = rect.top; | |
| 504 | - | isDragging = true; | |
| 505 | - | hasMoved = false; | |
| 506 | - | }, { passive: true }); | |
| 507 | - | ||
| 508 | - | dot.addEventListener('touchmove', (e) => { | |
| 509 | - | if (!isDragging) return; | |
| 510 | - | const touch = e.touches[0]; | |
| 511 | - | const dx = touch.clientX - startX; | |
| 512 | - | const dy = touch.clientY - startY; | |
| 513 | - | ||
| 514 | - | if (!hasMoved && Math.abs(dx) < 8 && Math.abs(dy) < 8) return; | |
| 515 | - | hasMoved = true; | |
| 516 | - | ||
| 517 | - | const newLeft = origLeft + dx; | |
| 518 | - | const newTop = origTop + dy; | |
| 519 | - | ||
| 520 | - | dot.style.transition = 'none'; | |
| 521 | - | dot.style.left = `${newLeft}px`; | |
| 522 | - | dot.style.top = `${newTop}px`; | |
| 523 | - | dot.style.right = 'auto'; | |
| 524 | - | dot.style.bottom = 'auto'; | |
| 525 | - | }, { passive: true }); | |
| 526 | - | ||
| 527 | - | dot.addEventListener('touchend', (e) => { | |
| 528 | - | if (!isDragging) return; | |
| 529 | - | isDragging = false; | |
| 530 | - | ||
| 531 | - | if (!hasMoved) { | |
| 532 | - | // It was a tap, not a drag — flag to skip the synthesized click | |
| 533 | - | handledByTouch = true; | |
| 534 | - | setTimeout(() => { handledByTouch = false; }, 300); | |
| 535 | - | toggleDial(); | |
| 536 | - | return; | |
| 537 | - | } | |
| 258 | + | // ============ More Popover ============ | |
| 538 | 259 | ||
| 539 | - | // Snap to nearest edge | |
| 540 | - | snapToEdge(dot); | |
| 541 | - | }, { passive: true }); | |
| 542 | - | } | |
| 260 | + | let morePopoverOpen = false; | |
| 543 | 261 | ||
| 544 | - | function snapToEdge(dot) { | |
| 545 | - | const rect = dot.getBoundingClientRect(); | |
| 546 | - | const cx = rect.left + rect.width / 2; | |
| 547 | - | const cy = rect.top + rect.height / 2; | |
| 548 | - | const vw = window.innerWidth; | |
| 549 | - | const vh = window.innerHeight; | |
| 550 | - | const safeBottom = parseInt(getComputedStyle(document.documentElement).getPropertyValue('env(safe-area-inset-bottom)')) || 0; | |
| 551 | - | const margin = 12; | |
| 552 | - | ||
| 553 | - | dot.style.transition = 'left 0.25s ease, top 0.25s ease, right 0.25s ease, bottom 0.25s ease'; | |
| 554 | - | ||
| 555 | - | // Snap horizontally to nearest edge | |
| 556 | - | if (cx < vw / 2) { | |
| 557 | - | dot.style.left = `${margin}px`; | |
| 558 | - | dot.style.right = 'auto'; | |
| 559 | - | } else { | |
| 560 | - | dot.style.left = 'auto'; | |
| 561 | - | dot.style.right = `${margin}px`; | |
| 262 | + | function toggleMorePopover() { | |
| 263 | + | const popover = document.getElementById('mobile-more-popover'); | |
| 264 | + | if (!popover) return; | |
| 265 | + | morePopoverOpen = !morePopoverOpen; | |
| 266 | + | popover.classList.toggle('visible', morePopoverOpen); | |
| 267 | + | if (morePopoverOpen) { | |
| 268 | + | document.addEventListener('click', closeMorePopover, { once: true }); | |
| 562 | 269 | } | |
| 270 | + | } | |
| 563 | 271 | ||
| 564 | - | // Clamp vertical position | |
| 565 | - | const clampedTop = Math.max(margin, Math.min(cy - rect.height / 2, vh - rect.height - margin - safeBottom)); | |
| 566 | - | dot.style.top = `${clampedTop}px`; | |
| 567 | - | dot.style.bottom = 'auto'; | |
| 272 | + | function closeMorePopover() { | |
| 273 | + | const popover = document.getElementById('mobile-more-popover'); | |
| 274 | + | if (popover) popover.classList.remove('visible'); | |
| 275 | + | morePopoverOpen = false; | |
| 568 | 276 | } | |
| 569 | 277 | ||
| 570 | 278 | // ============ Event Wiring ============ | |
| 571 | 279 | ||
| 572 | - | function initMobileNav() { | |
| 573 | - | const dot = document.getElementById('nav-dot'); | |
| 574 | - | const dial = document.getElementById('nav-dial'); | |
| 575 | - | const backdrop = document.getElementById('nav-dial-backdrop'); | |
| 576 | - | if (!dot || !dial) return; | |
| 577 | - | ||
| 578 | - | // Nav dot drag (touch) & tap (touch + mouse) | |
| 579 | - | initNavDotDrag(); | |
| 580 | - | dot.addEventListener('click', (e) => { | |
| 581 | - | e.stopPropagation(); | |
| 582 | - | if (handledByTouch) return; // Already handled by touchend | |
| 583 | - | toggleDial(); | |
| 584 | - | }); | |
| 280 | + | function initMobileTabBar() { | |
| 281 | + | const bar = document.getElementById('mobile-tab-bar'); | |
| 282 | + | if (!bar) return; | |
| 585 | 283 | ||
| 586 | - | // Dial item clicks | |
| 587 | - | dial.addEventListener('click', (e) => { | |
| 588 | - | const item = e.target.closest('.nav-dial-item'); | |
| 589 | - | if (!item) return; | |
| 590 | - | ||
| 591 | - | if (item.dataset.action === 'create') { | |
| 592 | - | newItemForCurrentView(); | |
| 593 | - | } else if (item.dataset.view) { | |
| 594 | - | switchView(item.dataset.view); | |
| 595 | - | } | |
| 284 | + | // Tab clicks | |
| 285 | + | bar.querySelectorAll('.mobile-tab[data-view]').forEach(tab => { | |
| 286 | + | tab.addEventListener('click', () => { | |
| 287 | + | switchView(tab.dataset.view); | |
| 288 | + | }); | |
| 596 | 289 | }); | |
| 597 | 290 | ||
| 598 | - | // Backdrop click closes dial | |
| 599 | - | if (backdrop) { | |
| 600 | - | backdrop.addEventListener('click', closeDial); | |
| 291 | + | // Create button | |
| 292 | + | const createBtn = document.getElementById('mobile-create-btn'); | |
| 293 | + | if (createBtn) { | |
| 294 | + | createBtn.addEventListener('click', () => { | |
| 295 | + | newItemForCurrentView(); | |
| 296 | + | }); | |
| 601 | 297 | } | |
| 602 | 298 | ||
| 603 | - | // Long-press on dial items to expand sub-views | |
| 604 | - | if (GoingsOn.touch?.addLongPress) { | |
| 605 | - | GoingsOn.touch.addLongPress(dial, (e) => { | |
| 606 | - | const item = e.target.closest('.nav-dial-item'); | |
| 607 | - | if (!item || item.classList.contains('nav-dial-center')) return; | |
| 608 | - | const tabName = item.dataset.view; | |
| 609 | - | if (SUB_VIEW_MAP[tabName]) { | |
| 610 | - | expandSubViews(tabName); | |
| 611 | - | } | |
| 299 | + | // More button + popover | |
| 300 | + | const moreBtn = document.getElementById('mobile-more-btn'); |
Lines truncated
| @@ -44,6 +44,10 @@ | |||
| 44 | 44 | ${themeOptions} | |
| 45 | 45 | </select> | |
| 46 | 46 | <p class="form-hint" style="margin-top: 0.5rem;">Choose a color theme for the interface.</p> | |
| 47 | + | <div style="display: flex; gap: 0.5rem; margin-top: 0.5rem;"> | |
| 48 | + | <button class="btn btn-small" onclick="GoingsOn.themes.importTheme()">Import Theme</button> | |
| 49 | + | <button class="btn btn-small" onclick="GoingsOn.themes.exportTheme()">Export Current</button> | |
| 50 | + | </div> | |
| 47 | 51 | </div> | |
| 48 | 52 | </div> | |
| 49 | 53 |
| @@ -51,6 +51,10 @@ class AppStateManager { | |||
| 51 | 51 | this.taskPage = 1; | |
| 52 | 52 | this.emailPage = 1; | |
| 53 | 53 | this.itemsPerPage = 50; | |
| 54 | + | ||
| 55 | + | // View switch tracking (in-memory only, reset on restart) | |
| 56 | + | this.viewSwitchCounts = {}; | |
| 57 | + | this.sessionStart = Date.now(); | |
| 54 | 58 | } | |
| 55 | 59 | ||
| 56 | 60 | /** |
| @@ -103,9 +103,11 @@ | |||
| 103 | 103 | }, | |
| 104 | 104 | { | |
| 105 | 105 | name: 'due', | |
| 106 | - | type: 'datetime-local', | |
| 106 | + | type: 'text', | |
| 107 | 107 | label: 'Due Date (optional)', | |
| 108 | + | placeholder: 'tomorrow, friday 3pm, 2026-12-25...', | |
| 108 | 109 | value: dueValue, | |
| 110 | + | transform: (v) => GoingsOn.utils.parseNaturalDate(v) || v, | |
| 109 | 111 | }, | |
| 110 | 112 | { | |
| 111 | 113 | name: 'tags', | |
| @@ -113,6 +115,7 @@ | |||
| 113 | 115 | label: 'Tags (comma-separated)', | |
| 114 | 116 | placeholder: 'work, urgent, meeting', | |
| 115 | 117 | value: tagsValue, | |
| 118 | + | transform: (v) => GoingsOn.utils.normalizeTags(v).join(', '), | |
| 116 | 119 | }, | |
| 117 | 120 | { | |
| 118 | 121 | name: 'recurrence', |
| @@ -190,6 +190,52 @@ | |||
| 190 | 190 | }); | |
| 191 | 191 | } | |
| 192 | 192 | ||
| 193 | + | // ============ Import / Export ============ | |
| 194 | + | ||
| 195 | + | /** | |
| 196 | + | * Import a custom theme TOML file via native file dialog. | |
| 197 | + | */ | |
| 198 | + | async function importTheme() { | |
| 199 | + | try { | |
| 200 | + | const { open } = window.__TAURI__.dialog; | |
| 201 | + | const path = await open({ | |
| 202 | + | filters: [{ name: 'Theme', extensions: ['toml'] }], | |
| 203 | + | multiple: false, | |
| 204 | + | }); | |
| 205 | + | if (!path) return; | |
| 206 | + | ||
| 207 | + | const meta = await invoke('import_theme', { path }); | |
| 208 | + | // Clear caches so new theme is discoverable | |
| 209 | + | GoingsOn.state.set('themeCache', {}); | |
| 210 | + | GoingsOn.state.set('themeList', []); | |
| 211 | + | GoingsOn.ui.showToast(`Imported "${meta.name}"`); | |
| 212 | + | await loadTheme(meta.id); | |
| 213 | + | } catch (e) { | |
| 214 | + | GoingsOn.ui.showToast('Import failed: ' + (e.message || e), 'error'); | |
| 215 | + | } | |
| 216 | + | } | |
| 217 | + | ||
| 218 | + | /** | |
| 219 | + | * Export the current theme TOML file via native save dialog. | |
| 220 | + | */ | |
| 221 | + | async function exportTheme() { | |
| 222 | + | const currentId = GoingsOn.state.currentThemeId; | |
| 223 | + | if (!currentId || currentId === 'system') return; | |
| 224 | + | try { | |
| 225 | + | const { save } = window.__TAURI__.dialog; | |
| 226 | + | const path = await save({ | |
| 227 | + | defaultPath: currentId + '.toml', | |
| 228 | + | filters: [{ name: 'Theme', extensions: ['toml'] }], | |
| 229 | + | }); | |
| 230 | + | if (!path) return; | |
| 231 | + | ||
| 232 | + | await invoke('export_theme', { id: currentId, path }); | |
| 233 | + | GoingsOn.ui.showToast('Theme exported'); | |
| 234 | + | } catch (e) { | |
| 235 | + | GoingsOn.ui.showToast('Export failed: ' + (e.message || e), 'error'); | |
| 236 | + | } | |
| 237 | + | } | |
| 238 | + | ||
| 193 | 239 | // ============ Populate GoingsOn.themes Namespace ============ | |
| 194 | 240 | ||
| 195 | 241 | GoingsOn.themes = { | |
| @@ -200,6 +246,8 @@ | |||
| 200 | 246 | getByType: getThemesByType, | |
| 201 | 247 | getCurrentId: getCurrentThemeId, | |
| 202 | 248 | getSystemPreference: getSystemThemePreference, | |
| 249 | + | importTheme, | |
| 250 | + | exportTheme, | |
| 203 | 251 | }; | |
| 204 | 252 | ||
| 205 | 253 | })(); |
| @@ -418,6 +418,123 @@ function autoGrow(textarea) { | |||
| 418 | 418 | resize(); | |
| 419 | 419 | } | |
| 420 | 420 | ||
| 421 | + | // ============ Natural Date Parsing ============ | |
| 422 | + | ||
| 423 | + | /** | |
| 424 | + | * Parse natural language date expressions into YYYY-MM-DDTHH:MM format. | |
| 425 | + | * Accepts: "today", "tomorrow", "yesterday", "next monday", "friday", | |
| 426 | + | * "friday 3pm", "next week", "in 3 days", "dec 25", "2026-12-25", | |
| 427 | + | * "2026-12-25 3pm", ISO format. | |
| 428 | + | * @param {string} str - Natural date string | |
| 429 | + | * @returns {string|null} - ISO datetime string or null if unparseable | |
| 430 | + | */ | |
| 431 | + | function parseNaturalDate(str) { | |
| 432 | + | if (!str) return null; | |
| 433 | + | const input = str.trim().toLowerCase(); | |
| 434 | + | if (!input) return null; | |
| 435 | + | ||
| 436 | + | // Already ISO format (YYYY-MM-DDTHH:MM or YYYY-MM-DD HH:MM) | |
| 437 | + | if (/^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}/.test(str.trim())) { | |
| 438 | + | const d = new Date(str.trim()); | |
| 439 | + | if (!isNaN(d)) return toLocalISOString(d); | |
| 440 | + | } | |
| 441 | + | ||
| 442 | + | // YYYY-MM-DD with optional time | |
| 443 | + | const dateMatch = input.match(/^(\d{4}-\d{2}-\d{2})(?:\s+(\d{1,2})(?::(\d{2}))?\s*(am|pm)?)?$/); | |
| 444 | + | if (dateMatch) { | |
| 445 | + | const d = new Date(dateMatch[1] + 'T12:00:00'); | |
| 446 | + | if (!isNaN(d)) { | |
| 447 | + | if (dateMatch[2]) applyTime(d, dateMatch[2], dateMatch[3], dateMatch[4]); | |
| 448 | + | else d.setHours(9, 0, 0, 0); | |
| 449 | + | return toLocalISOString(d); | |
| 450 | + | } | |
| 451 | + | } | |
| 452 | + | ||
| 453 | + | const now = new Date(); | |
| 454 | + | ||
| 455 | + | // Relative: today, tomorrow, yesterday | |
| 456 | + | if (input === 'today') { now.setHours(9, 0, 0, 0); return toLocalISOString(now); } | |
| 457 | + | if (input === 'tomorrow') { now.setDate(now.getDate() + 1); now.setHours(9, 0, 0, 0); return toLocalISOString(now); } | |
| 458 | + | if (input === 'yesterday') { now.setDate(now.getDate() - 1); now.setHours(9, 0, 0, 0); return toLocalISOString(now); } | |
| 459 | + | ||
| 460 | + | // "next week" = next Monday 9am | |
| 461 | + | if (input === 'next week') { | |
| 462 | + | const daysUntilMon = (8 - now.getDay()) % 7 || 7; | |
| 463 | + | now.setDate(now.getDate() + daysUntilMon); | |
| 464 | + | now.setHours(9, 0, 0, 0); | |
| 465 | + | return toLocalISOString(now); | |
| 466 | + | } | |
| 467 | + | ||
| 468 | + | // "in N days" | |
| 469 | + | const inDaysMatch = input.match(/^in\s+(\d+)\s+days?$/); | |
| 470 | + | if (inDaysMatch) { | |
| 471 | + | now.setDate(now.getDate() + parseInt(inDaysMatch[1])); | |
| 472 | + | now.setHours(9, 0, 0, 0); | |
| 473 | + | return toLocalISOString(now); | |
| 474 | + | } | |
| 475 | + | ||
| 476 | + | // Weekday names: "friday", "next friday", "friday 3pm" | |
| 477 | + | const days = ['sunday','monday','tuesday','wednesday','thursday','friday','saturday']; | |
| 478 | + | const dayMatch = input.match(/^(?:next\s+)?(sunday|monday|tuesday|wednesday|thursday|friday|saturday)(?:\s+(\d{1,2})(?::(\d{2}))?\s*(am|pm)?)?$/); | |
| 479 | + | if (dayMatch) { | |
| 480 | + | const targetDay = days.indexOf(dayMatch[1]); | |
| 481 | + | const isNext = input.startsWith('next'); | |
| 482 | + | let diff = targetDay - now.getDay(); | |
| 483 | + | if (diff <= 0 || isNext) diff += 7; | |
| 484 | + | if (isNext && diff <= 7) diff += 7; | |
| 485 | + | now.setDate(now.getDate() + diff); | |
| 486 | + | if (dayMatch[2]) applyTime(now, dayMatch[2], dayMatch[3], dayMatch[4]); | |
| 487 | + | else now.setHours(9, 0, 0, 0); | |
| 488 | + | return toLocalISOString(now); | |
| 489 | + | } | |
| 490 | + | ||
| 491 | + | // Month + day: "dec 25", "december 25", "jan 5 3pm" | |
| 492 | + | const months = ['january','february','march','april','may','june','july','august','september','october','november','december']; | |
| 493 | + | const monthAbbrs = ['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec']; | |
| 494 | + | const monthMatch = input.match(/^([a-z]+)\s+(\d{1,2})(?:\s+(\d{1,2})(?::(\d{2}))?\s*(am|pm)?)?$/); | |
| 495 | + | if (monthMatch) { | |
| 496 | + | let monthIdx = monthAbbrs.indexOf(monthMatch[1]); | |
| 497 | + | if (monthIdx === -1) monthIdx = months.indexOf(monthMatch[1]); | |
| 498 | + | if (monthIdx !== -1) { | |
| 499 | + | const d = new Date(now.getFullYear(), monthIdx, parseInt(monthMatch[2])); | |
| 500 | + | if (d < now) d.setFullYear(d.getFullYear() + 1); | |
| 501 | + | if (monthMatch[3]) applyTime(d, monthMatch[3], monthMatch[4], monthMatch[5]); | |
| 502 | + | else d.setHours(9, 0, 0, 0); | |
| 503 | + | return toLocalISOString(d); | |
| 504 | + | } | |
| 505 | + | } | |
| 506 | + | ||
| 507 | + | return null; | |
| 508 | + | } | |
| 509 | + | ||
| 510 | + | function applyTime(date, hours, minutes, ampm) { | |
| 511 | + | let h = parseInt(hours); | |
| 512 | + | const m = minutes ? parseInt(minutes) : 0; | |
| 513 | + | if (ampm === 'pm' && h < 12) h += 12; | |
| 514 | + | if (ampm === 'am' && h === 12) h = 0; | |
| 515 | + | date.setHours(h, m, 0, 0); | |
| 516 | + | } | |
| 517 | + | ||
| 518 | + | // ============ Tag Normalization ============ | |
| 519 | + | ||
| 520 | + | /** | |
| 521 | + | * Normalize a comma-separated tag string. | |
| 522 | + | * Splits on commas, trims whitespace, lowercases, filters empty, deduplicates. | |
| 523 | + | * @param {string} tagString - Raw tag string | |
| 524 | + | * @returns {string[]} - Array of clean tags | |
| 525 | + | */ | |
| 526 | + | function normalizeTags(tagString) { | |
| 527 | + | if (!tagString) return []; | |
| 528 | + | const seen = new Set(); | |
| 529 | + | return tagString.split(',') | |
| 530 | + | .map(t => t.trim().toLowerCase()) | |
| 531 | + | .filter(t => { | |
| 532 | + | if (!t || seen.has(t)) return false; | |
| 533 | + | seen.add(t); | |
| 534 | + | return true; | |
| 535 | + | }); | |
| 536 | + | } | |
| 537 | + | ||
| 421 | 538 | // ============ Populate GoingsOn.utils Namespace ============ | |
| 422 | 539 | ||
| 423 | 540 | GoingsOn.utils = { | |
| @@ -435,6 +552,12 @@ GoingsOn.utils = { | |||
| 435 | 552 | formatDateDisplay, | |
| 436 | 553 | toLocalISOString, | |
| 437 | 554 | ||
| 555 | + | // Natural date parsing | |
| 556 | + | parseNaturalDate, | |
| 557 | + | ||
| 558 | + | // Tag normalization | |
| 559 | + | normalizeTags, | |
| 560 | + | ||
| 438 | 561 | // Debounce | |
| 439 | 562 | debounce, | |
| 440 | 563 |
| @@ -39,6 +39,17 @@ | |||
| 39 | 39 | <div class="day-dots"> | |
| 40 | 40 | ${renderDayDots(day)} | |
| 41 | 41 | </div> | |
| 42 | + | ${(day.events && day.events.length > 0) ? ` | |
| 43 | + | <div class="day-events"> | |
| 44 | + | ${day.events.slice(0, 3).map(e => ` | |
| 45 | + | <div class="day-event" title="${escAttr(e.title)}"> | |
| 46 | + | <span class="event-time">${esc(e.formattedTime.split(' ').pop())}</span> | |
| 47 | + | ${esc(truncate(e.title, 12))} | |
| 48 | + | </div> | |
| 49 | + | `).join('')} | |
| 50 | + | ${day.events.length > 3 ? `<div class="day-event-more">+${day.events.length - 3}</div>` : ''} | |
| 51 | + | </div> | |
| 52 | + | ` : ''} | |
| 42 | 53 | </div> | |
| 43 | 54 | `).join('')} | |
| 44 | 55 | </div> | |
| @@ -80,6 +91,30 @@ | |||
| 80 | 91 | return dots.join(''); | |
| 81 | 92 | } | |
| 82 | 93 | ||
| 94 | + | function renderTimelineEvents(r) { | |
| 95 | + | const days = r.timelineDays || []; | |
| 96 | + | // Collect all events from timeline days, grouped by day | |
| 97 | + | const daysWithEvents = days.filter(d => d.events && d.events.length > 0); | |
| 98 | + | ||
| 99 | + | if (daysWithEvents.length === 0) return ''; | |
| 100 | + | ||
| 101 | + | return ` | |
| 102 | + | <div class="review-card week-timeline-events"> | |
| 103 | + | <div class="card-header"> | |
| 104 | + | <span class="card-title"> | |
| 105 | + | Week's Events | |
| 106 | + | </span> | |
| 107 | + | </div> | |
| 108 | + | ${daysWithEvents.map(day => ` | |
| 109 | + | <div class="timeline-events-day"> | |
| 110 | + | <div class="timeline-events-day-label">${esc(day.dayName)} ${day.dayNumber}</div> | |
| 111 | + | ${day.events.map(e => renderEventItemCompact(e)).join('')} | |
| 112 | + | </div> | |
| 113 | + | `).join('')} | |
| 114 | + | </div> | |
| 115 | + | `; | |
| 116 | + | } | |
| 117 | + | ||
| 83 | 118 | function renderAccomplished(r) { | |
| 84 | 119 | ||
| 85 | 120 | const count = r.tasksCompletedCount || 0; | |
| @@ -431,6 +466,7 @@ | |||
| 431 | 466 | ||
| 432 | 467 | GoingsOn.weeklyReviewRender = { | |
| 433 | 468 | renderWeekTimeline, | |
| 469 | + | renderTimelineEvents, | |
| 434 | 470 | renderAccomplished, | |
| 435 | 471 | renderNeedsAttention, | |
| 436 | 472 | renderComingUp, |
| @@ -92,6 +92,9 @@ | |||
| 92 | 92 | <!-- Week Timeline --> | |
| 93 | 93 | ${wr.renderWeekTimeline(r)} | |
| 94 | 94 | ||
| 95 | + | <!-- Week's Events (below timeline) --> | |
| 96 | + | ${wr.renderTimelineEvents(r)} | |
| 97 | + | ||
| 95 | 98 | <!-- Vacation Toggles --> | |
| 96 | 99 | ${wr.renderVacationToggles(r)} | |
| 97 | 100 | ||
| @@ -349,16 +352,30 @@ | |||
| 349 | 352 | function updateBadge(showBadge) { | |
| 350 | 353 | // Badge goes on the Time tab in the top nav | |
| 351 | 354 | const tab = document.querySelector('.tab-navigation [data-view="time"]'); | |
| 352 | - | if (!tab) return; | |
| 353 | - | ||
| 354 | - | const existingBadge = tab.querySelector('.tab-badge'); | |
| 355 | - | if (showBadge && !existingBadge) { | |
| 356 | - | const badge = document.createElement('span'); | |
| 357 | - | badge.className = 'tab-badge'; | |
| 358 | - | badge.setAttribute('aria-label', 'Review pending'); | |
| 359 | - | tab.appendChild(badge); | |
| 360 | - | } else if (!showBadge && existingBadge) { | |
| 361 | - | existingBadge.remove(); | |
| 355 | + | if (tab) { | |
| 356 | + | const existingBadge = tab.querySelector('.tab-badge'); | |
| 357 | + | if (showBadge && !existingBadge) { | |
| 358 | + | const badge = document.createElement('span'); | |
| 359 | + | badge.className = 'tab-badge'; | |
| 360 | + | badge.setAttribute('aria-label', 'Review pending'); | |
| 361 | + | tab.appendChild(badge); | |
| 362 | + | } else if (!showBadge && existingBadge) { | |
| 363 | + | existingBadge.remove(); | |
| 364 | + | } | |
| 365 | + | } | |
| 366 | + | ||
| 367 | + | // Also update the mobile tab bar | |
| 368 | + | const mobileTab = document.querySelector('.mobile-tab-bar [data-view="time"]'); | |
| 369 | + | if (mobileTab) { | |
| 370 | + | const existing = mobileTab.querySelector('.tab-badge'); | |
| 371 | + | if (showBadge && !existing) { | |
| 372 | + | const badge = document.createElement('span'); | |
| 373 | + | badge.className = 'tab-badge'; | |
| 374 | + | badge.setAttribute('aria-label', 'Review pending'); | |
| 375 | + | mobileTab.appendChild(badge); | |
| 376 | + | } else if (!showBadge && existing) { | |
| 377 | + | existing.remove(); | |
| 378 | + | } | |
| 362 | 379 | } | |
| 363 | 380 | } | |
| 364 | 381 |
| @@ -51,6 +51,39 @@ pub fn get_theme(app: AppHandle, id: String) -> Result<ThemeColors, ApiError> { | |||
| 51 | 51 | theme_common::load_theme(&dirs, &id).map_err(ApiError::internal) | |
| 52 | 52 | } | |
| 53 | 53 | ||
| 54 | + | #[tauri::command] | |
| 55 | + | #[instrument(skip_all)] | |
| 56 | + | pub fn get_custom_themes_dir(app: AppHandle) -> Result<String, ApiError> { | |
| 57 | + | let dir = app | |
| 58 | + | .path() | |
| 59 | + | .app_config_dir() | |
| 60 | + | .map_err(|e| ApiError::internal(e.to_string()))? | |
| 61 | + | .join("themes"); | |
| 62 | + | std::fs::create_dir_all(&dir) | |
| 63 | + | .map_err(|e| ApiError::internal(format!("Failed to create themes dir: {}", e)))?; | |
| 64 | + | Ok(dir.to_string_lossy().to_string()) | |
| 65 | + | } | |
| 66 | + | ||
| 67 | + | #[tauri::command] | |
| 68 | + | #[instrument(skip_all)] | |
| 69 | + | pub fn import_theme(app: AppHandle, path: String) -> Result<ThemeMeta, ApiError> { | |
| 70 | + | let custom_dir = app | |
| 71 | + | .path() | |
| 72 | + | .app_config_dir() | |
| 73 | + | .map_err(|e| ApiError::internal(e.to_string()))? | |
| 74 | + | .join("themes"); | |
| 75 | + | theme_common::import_theme(std::path::Path::new(&path), &custom_dir) | |
| 76 | + | .map_err(ApiError::internal) | |
| 77 | + | } | |
| 78 | + | ||
| 79 | + | #[tauri::command] | |
| 80 | + | #[instrument(skip_all)] | |
| 81 | + | pub fn export_theme(app: AppHandle, id: String, path: String) -> Result<(), ApiError> { | |
| 82 | + | let dirs = theme_dirs(&app); | |
| 83 | + | theme_common::export_theme(&dirs, &id, std::path::Path::new(&path)) | |
| 84 | + | .map_err(ApiError::internal) | |
| 85 | + | } | |
| 86 | + | ||
| 54 | 87 | #[cfg(test)] | |
| 55 | 88 | mod tests { | |
| 56 | 89 | // Core theme logic tests live in theme-common crate. |
| @@ -555,6 +555,9 @@ fn main() { | |||
| 555 | 555 | // Themes | |
| 556 | 556 | commands::list_themes, | |
| 557 | 557 | commands::get_theme, | |
| 558 | + | commands::get_custom_themes_dir, | |
| 559 | + | commands::import_theme, | |
| 560 | + | commands::export_theme, | |
| 558 | 561 | // Plugins | |
| 559 | 562 | commands::list_import_plugins, | |
| 560 | 563 | commands::list_enabled_import_plugins, |