Files
english/.opencode/skills/plans-kanban/assets/dashboard.css
2026-04-12 01:06:31 +07:00

1595 lines
30 KiB
CSS

/**
* Dashboard CSS - Refined Novel Theme
* Monochromatic warm palette with single accent color
* Clean, professional, premium aesthetic
*/
/* ========================================
Custom Properties - Warm Monochrome
======================================== */
:root {
/* Warm palette aligned with novel-theme.css */
--dash-bg: #FAF8F3;
--dash-surface: #FFFFFF;
--dash-surface-hover: #F5F3EE;
--dash-border: #E8E4DC;
--dash-border-subtle: #F0EDE6;
--dash-text: #2D2A26;
--dash-text-secondary: #7A756D;
--dash-text-muted: #A8A29E;
/* Single accent - warm brown */
--dash-accent: #8B4513;
--dash-accent-hover: #6B3410;
--dash-accent-subtle: rgba(139, 69, 19, 0.08);
--dash-accent-glow: rgba(139, 69, 19, 0.15);
/* Status - monochrome approach */
--dash-status-done: var(--dash-accent);
--dash-status-active: var(--dash-accent);
--dash-status-pending: var(--dash-text-muted);
/* Layout */
--dash-radius: 12px;
--dash-radius-sm: 8px;
--dash-shadow: 0 1px 3px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);
--dash-shadow-hover: 0 4px 12px rgba(0, 0, 0, 0.08);
/* Typography */
--dash-font: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
--dash-font-heading: 'Libre Baskerville', Georgia, serif;
/* Animation */
--dash-ease: cubic-bezier(0.4, 0, 0.2, 1);
--dash-duration: 200ms;
}
[data-theme="dark"] {
--dash-bg: #1A1A1A;
--dash-surface: #242424;
--dash-surface-hover: #2A2A2A;
--dash-border: #333333;
--dash-border-subtle: #2A2A2A;
--dash-text: #FAF8F3;
--dash-text-secondary: #A8A198;
--dash-text-muted: #6B6560;
/* Single accent - warm gold */
--dash-accent: #D4A574;
--dash-accent-hover: #E5B885;
--dash-accent-subtle: rgba(212, 165, 116, 0.1);
--dash-accent-glow: rgba(212, 165, 116, 0.2);
--dash-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
--dash-shadow-hover: 0 4px 12px rgba(0, 0, 0, 0.3);
}
/* ========================================
Base Layout
======================================== */
.dashboard-view {
min-height: 100vh;
background: var(--dash-bg);
font-family: var(--dash-font);
color: var(--dash-text);
}
/* ========================================
Header - Single Row Compact Layout
======================================== */
.dashboard-header {
position: sticky;
top: 0;
display: flex;
justify-content: space-between;
align-items: center;
gap: 1.5rem;
padding: 0.75rem 1.5rem;
background: var(--dash-surface);
border-bottom: 1px solid var(--dash-border);
z-index: 100;
}
.header-left {
display: flex;
align-items: center;
gap: 1.5rem;
flex-shrink: 0;
}
.dashboard-header h1 {
font-family: var(--dash-font-heading);
font-size: 1.25rem;
font-weight: 400;
color: var(--dash-text);
margin: 0;
letter-spacing: -0.01em;
}
/* Inline stats in header */
.header-stats {
display: flex;
align-items: center;
gap: 0.75rem;
font-size: 0.8125rem;
color: var(--dash-text-secondary);
}
.header-stat strong {
color: var(--dash-text);
font-weight: 600;
}
.header-stat-divider {
width: 1px;
height: 12px;
background: var(--dash-border);
}
/* Header controls - all in one row */
.header-controls {
display: flex;
align-items: center;
gap: 0.75rem;
flex-wrap: wrap;
}
/* Theme Toggle */
#theme-toggle {
width: 32px;
height: 32px;
border-radius: var(--dash-radius-sm);
background: transparent;
border: 1px solid var(--dash-border);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: var(--dash-text-secondary);
transition: all var(--dash-duration) var(--dash-ease);
flex-shrink: 0;
}
#theme-toggle:hover {
background: var(--dash-surface-hover);
color: var(--dash-text);
border-color: var(--dash-accent);
}
#theme-toggle svg {
width: 16px;
height: 16px;
}
/* ========================================
Controls (in header)
======================================== */
/* Search */
.search-box {
position: relative;
min-width: 160px;
max-width: 220px;
}
.search-box input {
width: 100%;
padding: 0.5rem 0.75rem 0.5rem 2rem;
border: 1px solid var(--dash-border);
border-radius: var(--dash-radius-sm);
background: var(--dash-bg);
color: var(--dash-text);
font-size: 0.8125rem;
font-family: var(--dash-font);
transition: all var(--dash-duration) var(--dash-ease);
}
.search-box input::placeholder {
color: var(--dash-text-muted);
}
.search-box input:focus {
outline: none;
border-color: var(--dash-accent);
box-shadow: 0 0 0 3px var(--dash-accent-subtle);
}
.search-icon {
position: absolute;
left: 0.625rem;
top: 50%;
transform: translateY(-50%);
color: var(--dash-text-muted);
pointer-events: none;
width: 14px;
height: 14px;
}
/* Sort Select */
#sort-select {
padding: 0.5rem 1.75rem 0.5rem 0.75rem;
border: 1px solid var(--dash-border);
border-radius: var(--dash-radius-sm);
background: var(--dash-bg);
color: var(--dash-text);
font-size: 0.8125rem;
font-family: var(--dash-font);
cursor: pointer;
appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%237A756D' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 0.5rem center;
transition: all var(--dash-duration) var(--dash-ease);
}
#sort-select:hover {
border-color: var(--dash-accent);
}
#sort-select:focus {
outline: none;
border-color: var(--dash-accent);
box-shadow: 0 0 0 3px var(--dash-accent-subtle);
}
/* Filter Pills - Simplified */
.filter-pills {
display: flex;
gap: 0.25rem;
padding: 3px;
background: var(--dash-bg);
border-radius: var(--dash-radius-sm);
border: 1px solid var(--dash-border);
}
.filter-pill {
padding: 0.3rem 0.625rem;
border: none;
border-radius: 5px;
background: transparent;
color: var(--dash-text-secondary);
font-size: 0.75rem;
font-weight: 500;
font-family: var(--dash-font);
cursor: pointer;
transition: all var(--dash-duration) var(--dash-ease);
}
.filter-pill:hover {
color: var(--dash-text);
background: var(--dash-surface-hover);
}
.filter-pill.active {
background: var(--dash-accent);
color: white;
}
/* Result Count */
.result-count {
font-size: 0.75rem;
color: var(--dash-text-muted);
}
.result-count strong {
color: var(--dash-text);
font-weight: 600;
}
/* View Toggle */
.view-toggle {
display: flex;
gap: 2px;
padding: 2px;
background: var(--dash-bg);
border-radius: 6px;
border: 1px solid var(--dash-border);
}
.view-toggle-btn {
padding: 0.3rem;
border: none;
border-radius: 4px;
background: transparent;
color: var(--dash-text-muted);
cursor: pointer;
transition: all var(--dash-duration) var(--dash-ease);
display: flex;
align-items: center;
justify-content: center;
}
.view-toggle-btn:hover {
color: var(--dash-text);
background: var(--dash-surface-hover);
}
.view-toggle-btn.active {
background: var(--dash-accent);
color: white;
}
.view-toggle-btn svg {
width: 16px;
height: 16px;
}
/* ========================================
Stats Hero - Minimal Version
======================================== */
.stats-hero {
display: none; /* Hidden - using inline stats instead */
}
/* ========================================
Kanban Board Layout (Vibe-Kanban Style)
======================================== */
.kanban-board {
display: grid;
grid-template-columns: repeat(5, minmax(240px, 1fr));
gap: 0;
min-height: calc(100vh - 160px);
overflow-x: auto;
}
.kanban-column {
display: flex;
flex-direction: column;
border-right: 1px solid var(--dash-border);
background: var(--dash-bg);
min-height: 100%;
}
.kanban-column:last-child {
border-right: none;
}
/* Column Header - Sticky */
.kanban-column-header {
position: sticky;
top: 0;
z-index: 10;
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.5rem;
padding: 0.875rem 1rem;
background: var(--dash-surface);
border-bottom: 1px dashed var(--dash-border);
}
.kanban-column-title {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.875rem;
font-weight: 500;
color: var(--dash-text);
}
.kanban-status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
flex-shrink: 0;
}
.kanban-status-dot.pending { background: var(--dash-text-muted); }
.kanban-status-dot.in-progress { background: #3B82F6; }
.kanban-status-dot.in-review { background: #F59E0B; }
.kanban-status-dot.completed { background: #10B981; }
.kanban-status-dot.cancelled { background: #EF4444; }
.kanban-column-count {
font-size: 0.75rem;
font-weight: 500;
color: var(--dash-text-muted);
background: var(--dash-bg);
padding: 0.125rem 0.5rem;
border-radius: 100px;
}
/* Column Cards Container */
.kanban-cards {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.5rem;
padding: 0.75rem;
overflow-y: auto;
}
/* Kanban Card - Compact */
.kanban-card {
background: var(--dash-surface);
border: 1px solid var(--dash-border);
border-radius: var(--dash-radius-sm);
padding: 0.875rem 1rem;
cursor: pointer;
transition: all var(--dash-duration) var(--dash-ease);
text-decoration: none;
color: inherit;
display: block;
}
.kanban-card:hover {
border-color: var(--dash-accent);
box-shadow: var(--dash-shadow-hover);
transform: translateY(-1px);
}
.kanban-card-title {
font-size: 0.875rem;
font-weight: 600;
color: var(--dash-text);
margin: 0 0 0.375rem 0;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.kanban-card-meta {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.75rem;
color: var(--dash-text-muted);
}
.kanban-card-progress {
display: flex;
align-items: center;
gap: 0.375rem;
}
.kanban-card-progress-bar {
width: 40px;
height: 3px;
background: var(--dash-border);
border-radius: 2px;
overflow: hidden;
}
.kanban-card-progress-fill {
height: 100%;
background: var(--dash-accent);
border-radius: 2px;
transition: width 0.3s var(--dash-ease);
}
.kanban-card-date {
margin-left: auto;
}
/* Kanban Card Enhanced - Description */
.kanban-card-description {
font-size: 0.75rem;
color: var(--dash-text-secondary);
line-height: 1.4;
margin: 0.25rem 0 0.5rem;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
/* Kanban Card Enhanced - Header with priority */
.kanban-card-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 0.5rem;
margin-bottom: 0.25rem;
}
.kanban-card-header .kanban-card-title {
margin: 0;
flex: 1;
}
/* Kanban Card Priority Badge */
.kanban-card-priority {
font-size: 0.625rem;
font-weight: 600;
padding: 0.125rem 0.375rem;
border-radius: 3px;
text-transform: uppercase;
letter-spacing: 0.02em;
flex-shrink: 0;
}
.kanban-card-priority.priority-high {
background: #FEE2E2;
color: #B91C1C;
}
.kanban-card-priority.priority-medium {
background: #FEF3C7;
color: #B45309;
}
.kanban-card-priority.priority-low {
background: #D1FAE5;
color: #047857;
}
[data-theme="dark"] .kanban-card-priority.priority-high {
background: rgba(185, 28, 28, 0.2);
color: #FCA5A5;
}
[data-theme="dark"] .kanban-card-priority.priority-medium {
background: rgba(180, 83, 9, 0.2);
color: #FCD34D;
}
[data-theme="dark"] .kanban-card-priority.priority-low {
background: rgba(4, 120, 87, 0.2);
color: #6EE7B7;
}
/* Kanban Card Tags */
.kanban-card-tags {
display: flex;
flex-wrap: wrap;
gap: 0.25rem;
margin-top: 0.5rem;
}
.kanban-card-tag {
font-size: 0.625rem;
padding: 0.125rem 0.375rem;
background: var(--dash-accent-subtle);
color: var(--dash-accent);
border-radius: 3px;
white-space: nowrap;
}
.kanban-card-tag.tag-more {
background: var(--dash-border);
color: var(--dash-text-muted);
}
/* Kanban Card Footer (effort + phases) */
.kanban-card-footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.5rem;
margin-top: 0.5rem;
padding-top: 0.5rem;
border-top: 1px solid var(--dash-border-subtle);
font-size: 0.6875rem;
color: var(--dash-text-muted);
}
.kanban-card-effort {
display: flex;
align-items: center;
gap: 0.25rem;
}
.kanban-card-effort svg {
width: 10px;
height: 10px;
opacity: 0.7;
}
.kanban-card-phases {
display: flex;
align-items: center;
gap: 0.25rem;
}
/* Empty Column State */
.kanban-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 2rem 1rem;
color: var(--dash-text-muted);
font-size: 0.8125rem;
text-align: center;
}
.kanban-empty-icon {
width: 32px;
height: 32px;
margin-bottom: 0.5rem;
opacity: 0.4;
}
/* ========================================
Plans Grid (Card View - Alternative)
======================================== */
.plans-grid {
display: none; /* Hidden when kanban is active */
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
gap: 1rem;
padding: 1.5rem 2rem 2rem;
}
/* Show grid when view mode is grid */
.view-mode-grid .plans-grid {
display: grid;
}
.view-mode-grid .kanban-board {
display: none;
}
/* Hide filter pills in kanban view - they only apply to grid view */
body:not(.view-mode-grid) .filter-pills {
display: none;
}
/* ========================================
Plan Cards - Clean Minimal Design
======================================== */
.plan-card {
background: var(--dash-surface);
border: 1px solid var(--dash-border);
border-radius: var(--dash-radius);
padding: 1.25rem 1.5rem;
cursor: pointer;
transition: all var(--dash-duration) var(--dash-ease);
position: relative;
}
.plan-card:hover {
border-color: var(--dash-accent);
box-shadow: var(--dash-shadow-hover);
transform: translateY(-2px);
}
.plan-card:active {
transform: translateY(0);
}
/* Subtle accent indicator */
.plan-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 3px;
height: 100%;
background: transparent;
border-radius: var(--dash-radius) 0 0 var(--dash-radius);
transition: background var(--dash-duration) var(--dash-ease);
}
.plan-card:hover::before {
background: var(--dash-accent);
}
/* Card completed state - always show accent */
.plan-card[data-status="completed"]::before {
background: var(--dash-accent);
}
/* Card Header */
.card-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 1rem;
gap: 1rem;
}
.card-header-content {
flex: 1;
min-width: 0;
}
.plan-name {
font-family: var(--dash-font);
font-size: 1rem;
font-weight: 600;
color: var(--dash-text);
margin: 0 0 0.375rem 0;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.plan-date {
font-size: 0.75rem;
color: var(--dash-text-muted);
display: flex;
align-items: center;
gap: 0.25rem;
}
.plan-date svg {
width: 12px;
height: 12px;
opacity: 0.6;
}
/* Status Icon - Monochrome */
.status-icon {
flex-shrink: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
color: var(--dash-text-muted);
}
.status-icon.completed {
color: var(--dash-accent);
}
.status-icon.in-progress {
color: var(--dash-accent);
}
/* Status badge - simplified */
.status-badge {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.25rem 0.625rem;
border-radius: 100px;
font-size: 0.6875rem;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.04em;
background: var(--dash-accent-subtle);
color: var(--dash-accent);
}
.status-badge.pending {
background: var(--dash-bg);
color: var(--dash-text-muted);
}
.status-badge::before {
content: '';
width: 5px;
height: 5px;
border-radius: 50%;
background: currentColor;
}
.status-badge.in-progress::before {
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
/* Card Body */
.card-body {
margin-bottom: 1rem;
}
/* Progress Bar - Simple horizontal */
.progress-bar {
display: flex;
height: 4px;
border-radius: 2px;
background: var(--dash-border);
overflow: hidden;
margin-bottom: 0.625rem;
}
.bar-segment {
height: 100%;
background: var(--dash-accent);
transition: width 0.4s var(--dash-ease);
}
.bar-segment.in-progress {
background: var(--dash-accent);
opacity: 0.6;
}
.bar-segment.pending {
background: transparent;
}
/* Phase count */
.phase-count {
font-size: 0.75rem;
color: var(--dash-text-secondary);
}
.phase-count strong {
color: var(--dash-text);
font-weight: 600;
}
/* Hide progress ring - using bar instead */
.progress-visual,
.progress-ring-container {
display: none;
}
/* Status counts - simplified */
.status-counts {
display: none; /* Hidden in new design */
}
/* Card Footer */
.card-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 1rem;
border-top: 1px solid var(--dash-border-subtle);
}
.phases-summary {
font-size: 0.75rem;
color: var(--dash-text-muted);
}
/* View Button - Ghost style */
.view-btn {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.5rem 0.875rem;
background: transparent;
color: var(--dash-accent);
text-decoration: none;
border: 1px solid var(--dash-accent);
border-radius: var(--dash-radius-sm);
font-size: 0.8125rem;
font-weight: 500;
transition: all var(--dash-duration) var(--dash-ease);
}
.view-btn:hover {
background: var(--dash-accent);
color: white;
}
.view-btn svg {
width: 14px;
height: 14px;
transition: transform var(--dash-duration) var(--dash-ease);
}
.view-btn:hover svg {
transform: translateX(2px);
}
/* ========================================
Empty State
======================================== */
.empty-state {
text-align: center;
padding: 4rem 2rem;
color: var(--dash-text-muted);
}
.empty-state[hidden] {
display: none;
}
.empty-icon {
width: 80px;
height: 80px;
margin: 0 auto 1.5rem;
background: var(--dash-bg);
border: 1px solid var(--dash-border);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: var(--dash-text-muted);
}
.empty-icon svg {
width: 32px;
height: 32px;
}
.empty-state h2 {
font-family: var(--dash-font);
font-size: 1.125rem;
font-weight: 600;
color: var(--dash-text-secondary);
margin-bottom: 0.5rem;
}
.empty-state p {
font-size: 0.875rem;
max-width: 320px;
margin: 0 auto;
line-height: 1.5;
}
/* ========================================
Loading Skeleton
======================================== */
.loading-skeleton {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
gap: 1rem;
padding: 1.5rem 2rem 2rem;
}
.plans-loaded .loading-skeleton {
display: none;
}
.skeleton-card {
height: 160px;
background: var(--dash-surface);
border: 1px solid var(--dash-border);
border-radius: var(--dash-radius);
position: relative;
overflow: hidden;
}
.skeleton-card::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(
90deg,
transparent 0%,
var(--dash-surface-hover) 50%,
transparent 100%
);
transform: translateX(-100%);
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
100% { transform: translateX(100%); }
}
/* ========================================
Accessibility
======================================== */
.plan-card:focus,
.filter-pill:focus,
.view-btn:focus,
#sort-select:focus,
#plan-search:focus,
#theme-toggle:focus {
outline: none;
}
.plan-card:focus-visible,
.filter-pill:focus-visible,
.view-btn:focus-visible,
#sort-select:focus-visible,
#plan-search:focus-visible,
#theme-toggle:focus-visible {
outline: 2px solid var(--dash-accent);
outline-offset: 2px;
}
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.skip-link {
position: absolute;
top: -100%;
left: 50%;
transform: translateX(-50%);
background: var(--dash-accent);
color: white;
padding: 0.75rem 1.5rem;
border-radius: 0 0 var(--dash-radius-sm) var(--dash-radius-sm);
z-index: 1000;
transition: top var(--dash-duration);
}
.skip-link:focus {
top: 0;
}
/* ========================================
Card Meta Tags (Duration, Effort, Priority, Issue)
======================================== */
.card-meta {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-top: 0.75rem;
padding-top: 0.75rem;
border-top: 1px solid var(--dash-border-subtle);
}
.meta-tag {
display: inline-flex;
align-items: center;
gap: 0.25rem;
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
font-weight: 500;
color: var(--dash-text-secondary);
background: var(--dash-bg);
border-radius: 4px;
text-decoration: none;
transition: all var(--dash-duration) var(--dash-ease);
}
.meta-tag svg {
flex-shrink: 0;
opacity: 0.7;
}
.meta-tag.duration {
color: var(--dash-text-secondary);
}
.meta-tag.effort {
color: var(--dash-accent);
background: var(--dash-accent-subtle);
}
.meta-tag.priority {
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.02em;
}
.meta-tag.priority.p1,
.meta-tag.priority.high,
.meta-tag.priority-high {
color: #fff;
background: #dc2626;
}
.meta-tag.priority.p2,
.meta-tag.priority.medium,
.meta-tag.priority-medium {
color: #000;
background: #facc15;
}
.meta-tag.priority.p3,
.meta-tag.priority.low,
.meta-tag.priority-low {
color: #fff;
background: #16a34a;
}
.meta-tag.issue {
color: var(--dash-text-secondary);
cursor: pointer;
text-decoration: none;
}
.meta-tag.issue:hover {
color: var(--dash-accent);
background: var(--dash-accent-subtle);
}
/* Card Description */
.card-description {
font-size: 0.85rem;
color: var(--dash-text-secondary);
margin: 0.5rem 0;
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* Card Tags */
.card-tags {
display: flex;
flex-wrap: wrap;
gap: 0.25rem;
margin-top: 0.5rem;
}
.tag-pill {
font-size: 0.7rem;
padding: 0.15rem 0.5rem;
border-radius: 9999px;
background: var(--dash-surface-hover);
color: var(--dash-text-secondary);
font-weight: 500;
}
.tag-pill:hover {
background: var(--dash-accent-subtle);
color: var(--dash-accent);
}
.tag-more {
background: var(--dash-border);
color: var(--dash-text-muted);
font-style: italic;
}
/* ========================================
Timeline Section - Layered Gantt (Minimal)
======================================== */
.timeline-section {
padding: 1rem 1.5rem;
margin: 1rem 1.5rem;
background: var(--dash-surface);
border-radius: var(--dash-radius);
border: 1px solid var(--dash-border);
}
.timeline-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
}
.timeline-title {
font-family: var(--dash-font);
font-size: 0.75rem;
font-weight: 600;
color: var(--dash-text-muted);
text-transform: uppercase;
letter-spacing: 0.04em;
margin: 0;
display: inline;
}
/* Remove decorative lines from novel-theme h2 */
.timeline-title::before,
.timeline-title::after {
display: none;
}
.timeline-controls {
display: flex;
gap: 0.5rem;
}
.timeline-zoom-btn {
padding: 0.25rem 0.625rem;
font-size: 0.6875rem;
font-weight: 500;
color: var(--dash-text-muted);
background: transparent;
border: 1px solid var(--dash-border);
border-radius: 4px;
cursor: pointer;
transition: all var(--dash-duration) var(--dash-ease);
}
.timeline-zoom-btn:hover,
.timeline-zoom-btn.active {
color: var(--dash-accent);
border-color: var(--dash-accent);
background: var(--dash-accent-subtle);
}
.timeline-stats {
display: flex;
gap: 1rem;
font-size: 0.75rem;
color: var(--dash-text-muted);
}
.timeline-stat {
display: flex;
align-items: center;
gap: 0.25rem;
}
.timeline-stat strong {
color: var(--dash-text-secondary);
font-weight: 600;
}
/* Gantt Container */
.gantt-container {
position: relative;
margin-top: 0.25rem;
}
/* Date Axis */
.gantt-axis {
display: flex;
justify-content: space-between;
padding: 0 0 0.375rem;
border-bottom: 1px solid var(--dash-border-subtle);
margin-bottom: 0.5rem;
}
.gantt-axis-label {
font-size: 0.6875rem;
font-weight: 500;
color: var(--dash-text-muted);
text-transform: uppercase;
letter-spacing: 0.03em;
}
.gantt-axis-label.today {
color: var(--dash-accent);
font-weight: 600;
}
/* Gantt Track (where bars live) */
.gantt-track {
position: relative;
min-height: 60px;
max-height: 220px;
overflow-y: auto;
overflow-x: hidden;
background:
repeating-linear-gradient(
90deg,
transparent,
transparent calc(100% / 7 - 1px),
var(--dash-border-subtle) calc(100% / 7 - 1px),
var(--dash-border-subtle) calc(100% / 7)
);
}
.gantt-track::-webkit-scrollbar {
width: 4px;
}
.gantt-track::-webkit-scrollbar-thumb {
background: var(--dash-border);
border-radius: 2px;
}
/* Gantt Bar - Compact 18px height, clickable link */
.gantt-bar {
position: absolute;
height: 18px;
border-radius: 4px;
cursor: pointer;
transition: all 0.15s var(--dash-ease);
display: flex;
align-items: center;
padding: 0 0.375rem;
overflow: hidden;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
text-decoration: none;
color: inherit;
}
.gantt-bar:hover {
transform: translateY(-1px);
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
z-index: 10;
}
.gantt-bar.completed {
background: var(--dash-accent);
color: #fff;
font-weight: 600;
}
.gantt-bar.in-progress {
background: var(--dash-accent);
color: #fff;
font-weight: 600;
}
.gantt-bar.in-progress::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(
90deg,
transparent 0%,
rgba(255, 255, 255, 0.2) 50%,
transparent 100%
);
animation: shimmer 2s ease-in-out infinite;
}
@keyframes shimmer {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
.gantt-bar.pending {
background: var(--dash-bg);
border: 1px solid var(--dash-border);
color: var(--dash-text);
font-weight: 500;
}
.gantt-bar-label {
font-size: 0.625rem;
font-weight: inherit;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
position: relative;
z-index: 1;
}
.gantt-bar-status {
margin-left: auto;
font-size: 0.5625rem;
opacity: 0.8;
flex-shrink: 0;
}
/* Gantt Tooltip */
.gantt-tooltip {
position: absolute;
bottom: calc(100% + 8px);
left: 50%;
transform: translateX(-50%);
background: var(--dash-text);
color: var(--dash-bg);
padding: 0.5rem 0.75rem;
border-radius: 6px;
font-size: 0.75rem;
white-space: nowrap;
opacity: 0;
visibility: hidden;
transition: all 0.15s ease;
z-index: 100;
pointer-events: none;
}
.gantt-tooltip::after {
content: '';
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
border: 5px solid transparent;
border-top-color: var(--dash-text);
}
.gantt-bar:hover .gantt-tooltip {
opacity: 1;
visibility: visible;
}
.gantt-tooltip-title {
font-weight: 600;
margin-bottom: 0.25rem;
}
.gantt-tooltip-meta {
display: flex;
gap: 0.75rem;
opacity: 0.8;
font-size: 0.6875rem;
}
/* Today Marker */
.gantt-today-marker {
position: absolute;
top: 0;
bottom: 0;
width: 2px;
background: var(--dash-accent);
z-index: 5;
opacity: 0.6;
}
.gantt-today-marker::before {
content: 'Today';
position: absolute;
top: -1.25rem;
left: 50%;
transform: translateX(-50%);
font-size: 0.5625rem;
font-weight: 600;
color: var(--dash-accent);
text-transform: uppercase;
letter-spacing: 0.05em;
}
/* Empty State */
.gantt-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 80px;
color: var(--dash-text-muted);
font-size: 0.8125rem;
}
/* Compact Summary */
.timeline-summary {
display: flex;
gap: 0.75rem;
margin-top: 0.5rem;
padding-top: 0.5rem;
border-top: 1px solid var(--dash-border-subtle);
font-size: 0.6875rem;
color: var(--dash-text-muted);
}
.timeline-summary-item {
display: flex;
align-items: center;
gap: 0.375rem;
}
.timeline-summary-dot {
width: 6px;
height: 6px;
border-radius: 50%;
}
.timeline-summary-dot.completed {
background: var(--dash-accent);
}
.timeline-summary-dot.in-progress {
background: var(--dash-accent);
opacity: 0.6;
}
.timeline-summary-dot.pending {
background: var(--dash-border);
}
/* ========================================
Reduced Motion
======================================== */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* ========================================
Responsive
======================================== */
@media (max-width: 768px) {
.dashboard-header {
padding: 1rem 1.25rem;
flex-wrap: wrap;
gap: 0.75rem;
}
.header-left {
flex-direction: column;
align-items: flex-start;
gap: 0.5rem;
}
.header-stats {
font-size: 0.8125rem;
}
.dashboard-controls {
padding: 1rem 1.25rem;
gap: 0.75rem;
}
.search-box {
min-width: 100%;
max-width: 100%;
}
#sort-select {
flex: 1;
}
.filter-pills {
width: 100%;
justify-content: center;
}
.result-count {
width: 100%;
text-align: center;
margin-left: 0;
}
.plans-grid {
grid-template-columns: 1fr;
padding: 1rem 1.25rem;
}
}
@media (max-width: 480px) {
.dashboard-header h1 {
font-size: 1.25rem;
}
.header-stat-divider {
display: none;
}
.header-stats {
flex-wrap: wrap;
gap: 0.5rem 1rem;
}
.filter-pill {
padding: 0.375rem 0.625rem;
font-size: 0.75rem;
}
.plan-card {
padding: 1rem 1.25rem;
}
}
/* ========================================
Print Styles
======================================== */
@media print {
.dashboard-header,
.dashboard-controls,
.loading-skeleton,
#theme-toggle {
display: none !important;
}
.dashboard-view {
background: white;
}
.plans-grid {
display: block;
padding: 0;
}
.plan-card {
break-inside: avoid;
margin-bottom: 1rem;
box-shadow: none;
border: 1px solid #ddd;
}
.plan-card:hover {
transform: none;
box-shadow: none;
}
.plan-card::before {
display: none;
}
}