:root { color-scheme: light; --background: hsl(36 33% 97%); --foreground: hsl(222 33% 15%); --card: hsl(0 0% 100%); --line: hsl(32 18% 84%); --line-strong: hsl(32 18% 76%); --primary: hsl(198 78% 37%); --primary-soft: hsl(198 52% 90%); --cyan: hsl(192 85% 55%); --pink: hsl(338 82% 62%); --text-muted: hsl(220 13% 40%); --shadow-1: 0 1px 2px 0 rgb(23 32 46 / 0.06); --shadow-2: 0 12px 30px -12px rgb(23 32 46 / 0.22); } .dark { color-scheme: dark; --background: hsl(222 35% 10%); --foreground: hsl(38 20% 92%); --card: hsl(221 31% 13%); --line: hsl(219 18% 25%); --line-strong: hsl(219 18% 33%); --primary: hsl(194 76% 62%); --primary-soft: hsl(210 34% 24%); --cyan: hsl(192 85% 55%); --pink: hsl(338 82% 62%); --text-muted: hsl(218 17% 72%); --shadow-1: 0 1px 2px 0 rgb(2 8 18 / 0.35); --shadow-2: 0 12px 30px -12px rgb(2 8 18 / 0.55); } * { box-sizing: border-box; } body { margin: 0; color: var(--foreground); font-family: "Avenir Next", "Segoe UI", "Noto Sans", sans-serif; background: var(--background); min-height: 100vh; } body::before { content: ""; position: fixed; inset: 0; pointer-events: none; background-image: linear-gradient(112deg, hsl(198 78% 37% / 0.14) 0%, hsl(192 85% 55% / 0.11) 28%, transparent 56%), linear-gradient(248deg, hsl(338 82% 62% / 0.11) 0%, transparent 46%), repeating-linear-gradient(135deg, hsl(222 33% 15% / 0.035) 0 1px, transparent 1px 11px); opacity: 1; } main { position: relative; max-width: 1050px; margin: 0 auto; padding: 28px 22px 40px; } h1, h2, h3 { font-family: "Baskerville", "Times New Roman", serif; letter-spacing: 0.01em; } .top-nav { position: sticky; top: 0; z-index: 3; display: flex; justify-content: space-between; align-items: center; gap: 18px; padding: 14px 22px; border-bottom: 1px solid hsl(198 78% 37% / 0.25); background: hsl(36 33% 97% / 0.72); backdrop-filter: blur(10px); box-shadow: var(--shadow-1); } .brand { display: flex; align-items: center; gap: 10px; text-decoration: none; color: var(--foreground); } .brand img { border-radius: 8px; box-shadow: 0 8px 24px -10px rgb(23 32 46 / 0.35); } .brand-name { background: linear-gradient(90deg, var(--primary), var(--cyan), var(--pink)); -webkit-background-clip: text; background-clip: text; color: transparent; font-size: 1.02rem; font-weight: 800; letter-spacing: 0.06em; } .brand-subtitle { margin-left: -4px; text-transform: uppercase; letter-spacing: 0.12em; font-size: 0.68rem; color: var(--text-muted); font-weight: 700; } .links { display: flex; gap: 14px; } .links-wrap { display: flex; align-items: center; gap: 10px; } a { color: var(--primary); text-decoration: none; font-weight: 700; } .links a { padding: 7px 10px; border-radius: 8px; } .links a:hover { background: hsl(198 52% 90% / 0.65); color: hsl(222 33% 15%); } table { width: 100%; border-collapse: collapse; background: hsl(0 0% 100% / 0.95); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; box-shadow: var(--shadow-2); } th, td { padding: 10px; border-bottom: 1px solid hsl(32 18% 86%); text-align: left; } th { color: hsl(222 33% 18%); background: hsl(36 30% 95%); } code, pre { font-family: "JetBrains Mono", "SF Mono", monospace; } pre { margin: 10px 0 0; white-space: pre-wrap; word-break: break-all; background: hsl(36 24% 93%); border: 1px solid var(--line); border-radius: 8px; padding: 10px; } form.inline { display: inline; } input, select, button { border-radius: 8px; padding: 8px 10px; margin: 4px 8px 4px 0; border: 1px solid var(--line-strong); background: white; color: var(--foreground); } button { border: 1px solid hsl(198 78% 37% / 0.45); background: linear-gradient(95deg, hsl(198 78% 37% / 0.12), hsl(192 85% 55% / 0.15)); color: hsl(222 33% 16%); cursor: pointer; font-weight: 700; } button:hover { box-shadow: 0 6px 20px -10px hsl(198 78% 37% / 0.5); } .theme-toggle { min-width: 66px; } .cancel-btn { background: linear-gradient(95deg, hsl(2 72% 48% / 0.15), hsl(338 82% 62% / 0.2)); border-color: hsl(2 72% 48% / 0.5); } .scan-btn { background: linear-gradient(95deg, hsl(142 60% 45% / 0.15), hsl(142 60% 55% / 0.2)); border-color: hsl(142 60% 45% / 0.5); padding: 4px 12px; font-size: 0.85rem; } .delete-btn { background: linear-gradient(95deg, hsl(2 72% 48% / 0.15), hsl(338 82% 62% / 0.2)); border-color: hsl(2 72% 48% / 0.5); padding: 4px 12px; font-size: 0.85rem; } .full-rebuild-btn { background: linear-gradient(95deg, hsl(280 60% 45% / 0.15), hsl(280 60% 55% / 0.2)); border-color: hsl(280 60% 45% / 0.5); } .status-pending { color: hsl(45 93% 47%); } .status-running { color: hsl(192 85% 55%); } .status-completed { color: hsl(142 60% 45%); } .status-failed { color: hsl(2 72% 48%); } .status-cancelled { color: hsl(220 13% 40%); } .error-hint { display: inline-block; margin-left: 6px; width: 16px; height: 16px; line-height: 16px; text-align: center; border-radius: 50%; background: hsl(2 72% 48%); color: white; font-size: 11px; font-weight: bold; cursor: help; } .card { background: var(--card); border: 1px solid var(--line); border-radius: 14px; padding: 16px; margin: 16px 0; box-shadow: var(--shadow-2); } .dark .top-nav { background: hsl(222 35% 10% / 0.72); border-bottom-color: hsl(194 76% 62% / 0.3); } .dark .links a:hover { background: hsl(210 34% 24% / 0.8); color: hsl(38 20% 92%); } .dark table { background: hsl(221 31% 13% / 0.95); } .dark th { color: hsl(38 20% 92%); background: hsl(221 24% 17%); } .dark th, .dark td { border-bottom-color: hsl(219 18% 22%); } .dark input, .dark select, .dark button { background: hsl(221 31% 13%); color: hsl(38 20% 92%); } .dark pre { background: hsl(221 24% 17%); } @media (max-width: 720px) { .top-nav { flex-direction: column; align-items: flex-start; } .links-wrap { width: 100%; justify-content: space-between; } .links { flex-wrap: wrap; } .brand span { font-size: 14px; } main { padding: 18px 14px 30px; } } /* Books page styles */ .search-form { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; } .search-input { flex: 1; min-width: 200px; } .results-info { color: var(--text-muted); margin: 16px 0; font-size: 0.95rem; } .books-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 24px; margin: 24px 0; } .book-card { display: flex; flex-direction: column; text-decoration: none; color: var(--foreground); background: var(--card); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; transition: transform 0.2s ease, box-shadow 0.2s ease; box-shadow: var(--shadow-1); } .book-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-2); } .book-cover { position: relative; aspect-ratio: 2/3; background: linear-gradient(135deg, hsl(36 24% 93%), hsl(36 24% 88%)); overflow: hidden; } .cover-image { width: 100%; height: 100%; object-fit: cover; } .book-info { padding: 12px; flex: 1; display: flex; flex-direction: column; gap: 4px; } .book-title { font-size: 0.95rem; font-weight: 700; margin: 0; line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; font-family: "Avenir Next", "Segoe UI", sans-serif; letter-spacing: normal; } .book-author { font-size: 0.85rem; color: var(--text-muted); margin: 0; } .book-series { font-size: 0.8rem; color: var(--primary); margin: 0; } .book-meta { display: flex; gap: 8px; margin-top: auto; padding-top: 8px; } .book-kind { font-size: 0.7rem; padding: 2px 6px; border-radius: 4px; font-weight: 700; background: hsl(198 52% 90%); color: hsl(198 78% 37%); } .book-kind.cbz { background: hsl(142 60% 90%); color: hsl(142 60% 35%); } .book-kind.cbr { background: hsl(45 93% 90%); color: hsl(45 93% 35%); } .book-kind.pdf { background: hsl(2 72% 90%); color: hsl(2 72% 45%); } .book-lang { font-size: 0.7rem; padding: 2px 6px; border-radius: 4px; background: var(--line); color: var(--text-muted); } .pagination { display: flex; justify-content: center; margin: 32px 0; } .empty-state { text-align: center; padding: 48px 24px; color: var(--text-muted); } /* Book detail page */ .breadcrumb { margin-bottom: 24px; } .breadcrumb a { color: var(--text-muted); font-size: 0.9rem; } .breadcrumb a:hover { color: var(--primary); } .book-detail { display: grid; grid-template-columns: 300px 1fr; gap: 32px; align-items: start; } @media (max-width: 720px) { .book-detail { grid-template-columns: 1fr; } } .book-detail-cover { border-radius: 12px; overflow: hidden; box-shadow: var(--shadow-2); } .detail-cover-image { width: 100%; height: auto; display: block; } .book-detail-info h1 { margin: 0 0 16px 0; font-size: 1.8rem; line-height: 1.2; } .detail-author { font-size: 1.1rem; color: var(--text-muted); margin: 0 0 16px 0; } .detail-series { font-size: 1rem; color: var(--primary); margin: 0 0 24px 0; } .detail-series .volume { margin-left: 12px; padding: 4px 10px; background: var(--primary-soft); border-radius: 6px; font-size: 0.85rem; color: var(--foreground); } .detail-meta { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 20px; box-shadow: var(--shadow-1); } .meta-row { display: flex; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--line); } .meta-row:last-child { border-bottom: none; } .meta-label { font-weight: 700; color: var(--text-muted); min-width: 100px; } .book-id { font-size: 0.85rem; color: var(--text-muted); } .dark .book-cover { background: linear-gradient(135deg, hsl(221 24% 20%), hsl(221 24% 15%)); } .dark .book-kind { background: hsl(198 52% 25%); color: hsl(198 78% 75%); } .dark .book-kind.cbz { background: hsl(142 60% 25%); color: hsl(142 60% 65%); } .dark .book-kind.cbr { background: hsl(45 93% 25%); color: hsl(45 93% 65%); } .dark .book-kind.pdf { background: hsl(2 72% 25%); color: hsl(2 72% 65%); } /* Library info styles */ .library-info { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 16px 20px; margin: 16px 0 24px 0; box-shadow: var(--shadow-1); } .library-info p { margin: 0; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; } .library-info code { font-size: 0.9rem; } .library-info .separator { color: var(--line-strong); font-weight: 300; } .status-enabled { color: hsl(142 60% 45%); font-weight: 700; } .status-disabled { color: hsl(220 13% 40%); font-weight: 700; } .book-count-link { color: var(--primary); text-decoration: none; font-weight: 700; padding: 2px 8px; border-radius: 6px; transition: background 0.2s ease; } .book-count-link:hover { background: var(--primary-soft); } .series-count-link { color: var(--primary); text-decoration: none; font-weight: 700; padding: 2px 8px; border-radius: 6px; transition: background 0.2s ease; } .series-count-link:hover { background: var(--primary-soft); } .dark .status-enabled { color: hsl(142 60% 65%); } .dark .status-disabled { color: hsl(218 17% 72%); } /* Series grid styles */ .series-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 24px; margin: 24px 0; } .series-card { display: flex; flex-direction: column; text-decoration: none; color: var(--foreground); background: var(--card); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; transition: transform 0.2s ease, box-shadow 0.2s ease; box-shadow: var(--shadow-1); } .series-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-2); } .series-cover { position: relative; aspect-ratio: 2/3; background: linear-gradient(135deg, hsl(36 24% 93%), hsl(36 24% 88%)); overflow: hidden; } .series-cover-image { width: 100%; height: 100%; object-fit: cover; } .series-info { padding: 12px; flex: 1; display: flex; flex-direction: column; gap: 4px; } .series-name { font-size: 0.95rem; font-weight: 700; margin: 0; line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; font-family: "Avenir Next", "Segoe UI", sans-serif; letter-spacing: normal; } .series-count { font-size: 0.85rem; color: var(--text-muted); margin: 0; margin-top: auto; } .dark .series-cover { background: linear-gradient(135deg, hsl(221 24% 20%), hsl(221 24% 15%)); } /* Status badges */ .status-ok { color: hsl(142 60% 45%); font-weight: 700; } .status-error { color: hsl(2 72% 48%); font-weight: 700; } .status-pending { color: hsl(45 93% 47%); font-weight: 700; } .file-path { font-size: 0.8rem; word-break: break-all; max-width: 400px; display: inline-block; } /* Job Progress Component */ .job-progress { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 16px; margin: 8px 0; } .progress-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; } .status-badge { padding: 4px 10px; border-radius: 6px; font-size: 0.8rem; font-weight: 700; text-transform: uppercase; } .status-badge.status-pending { background: hsl(45 93% 90%); color: hsl(45 93% 35%); } .status-badge.status-running { background: hsl(198 52% 90%); color: hsl(198 78% 37%); } .status-badge.status-success { background: hsl(142 60% 90%); color: hsl(142 60% 35%); } .status-badge.status-failed { background: hsl(2 72% 90%); color: hsl(2 72% 45%); } .status-badge.status-cancelled { background: hsl(220 13% 90%); color: hsl(220 13% 40%); } .complete-badge { padding: 4px 10px; border-radius: 6px; font-size: 0.75rem; font-weight: 700; background: hsl(142 60% 90%); color: hsl(142 60% 35%); } .progress-bar-container { position: relative; height: 24px; background: var(--line); border-radius: 12px; overflow: hidden; margin-bottom: 12px; } .progress-bar-fill { height: 100%; background: linear-gradient(90deg, hsl(198 78% 37%), hsl(192 85% 55%)); border-radius: 12px; transition: width 0.3s ease; } .progress-percent { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); font-size: 0.8rem; font-weight: 700; color: var(--foreground); } .progress-stats { display: flex; justify-content: space-between; align-items: center; font-size: 0.9rem; color: var(--text-muted); } .current-file { font-size: 0.8rem; max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .progress-detailed-stats { display: flex; gap: 16px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); font-size: 0.85rem; } .error-count { color: hsl(2 72% 48%); font-weight: 700; } .progress-row { background: hsl(198 52% 95%); } .progress-row td { padding: 0; } .toggle-progress-btn { margin-left: 8px; padding: 2px 8px; font-size: 0.75rem; background: transparent; border: 1px solid var(--line); } /* Jobs Indicator */ .jobs-indicator-container { position: relative; } .jobs-indicator { position: relative; display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; padding: 0; border-radius: 8px; background: transparent; border: 1px solid var(--line); color: var(--foreground); cursor: pointer; transition: all 0.2s ease; } .jobs-indicator:hover { background: hsl(198 52% 90% / 0.5); } .jobs-indicator.active { border-color: hsl(198 78% 37% / 0.5); } .jobs-badge { position: absolute; top: -4px; right: -4px; min-width: 18px; height: 18px; padding: 0 5px; background: hsl(2 72% 48%); color: white; font-size: 0.7rem; font-weight: 700; border-radius: 9px; display: flex; align-items: center; justify-content: center; } .jobs-pulse { position: absolute; bottom: 2px; left: 2px; width: 8px; height: 8px; background: hsl(142 60% 45%); border-radius: 50%; animation: pulse 2s infinite; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } .jobs-dropdown { position: absolute; top: 100%; right: 0; margin-top: 8px; min-width: 320px; max-width: 400px; background: var(--card); border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow-2); z-index: 100; padding: 16px; } .jobs-dropdown-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; padding-bottom: 12px; border-bottom: 1px solid var(--line); } .jobs-dropdown-header a { font-size: 0.85rem; } .jobs-empty { text-align: center; color: var(--text-muted); padding: 16px; } .jobs-list { list-style: none; margin: 0; padding: 0; max-height: 300px; overflow-y: auto; } .job-item { padding: 12px; border-bottom: 1px solid var(--line); } .job-item:last-child { border-bottom: none; } .job-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; } .job-id { font-size: 0.75rem; color: var(--text-muted); } .job-status { font-size: 0.7rem; padding: 2px 6px; border-radius: 4px; font-weight: 700; text-transform: uppercase; } .job-status.status-pending { background: hsl(45 93% 90%); color: hsl(45 93% 35%); } .job-status.status-running { background: hsl(198 52% 90%); color: hsl(198 78% 37%); } .job-mini-progress { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; } .job-progress-bar { flex: 1; height: 6px; background: hsl(198 78% 37%); border-radius: 3px; } .job-mini-progress span { font-size: 0.75rem; color: var(--text-muted); min-width: 35px; } .job-file { margin: 0; font-size: 0.75rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .progress-loading, .progress-error { padding: 16px; text-align: center; color: var(--text-muted); } .progress-error { color: hsl(2 72% 48%); } /* Dark mode overrides for new components */ .dark .status-badge.status-pending { background: hsl(45 93% 25%); color: hsl(45 93% 65%); } .dark .status-badge.status-running { background: hsl(198 52% 25%); color: hsl(198 78% 75%); } .dark .status-badge.status-success { background: hsl(142 60% 25%); color: hsl(142 60% 65%); } .dark .status-badge.status-failed { background: hsl(2 72% 25%); color: hsl(2 72% 65%); } .dark .status-badge.status-cancelled { background: hsl(220 13% 25%); color: hsl(220 13% 65%); } .dark .complete-badge { background: hsl(142 60% 25%); color: hsl(142 60% 65%); } .dark .progress-row { background: hsl(198 52% 15%); } .dark .jobs-indicator:hover { background: hsl(210 34% 24% / 0.5); } .dark .job-status.status-pending { background: hsl(45 93% 25%); color: hsl(45 93% 65%); } .dark .job-status.status-running { background: hsl(198 52% 25%); color: hsl(198 78% 75%); } /* Progress bar visibility fix */ .job-progress { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 16px; margin: 8px 0; min-height: 120px; } .progress-bar-container { position: relative; height: 24px; background: hsl(220 13% 90%); border-radius: 12px; overflow: hidden; margin: 12px 0; } .progress-bar-fill { height: 100%; background: linear-gradient(90deg, hsl(198 78% 37%), hsl(192 85% 55%)); border-radius: 12px; transition: width 0.5s ease; min-width: 2px; } .progress-percent { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); font-size: 0.85rem; font-weight: 700; color: var(--foreground); text-shadow: 0 0 2px rgba(255,255,255,0.5); } .progress-row { background: hsl(198 52% 95%); } .progress-row td { padding: 0; } /* Highlighted job row */ tr.job-highlighted { background: hsl(198 78% 95%); box-shadow: inset 0 0 0 2px hsl(198 78% 37%); } tr.job-highlighted td { animation: pulse-border 2s ease-in-out infinite; } @keyframes pulse-border { 0%, 100% { box-shadow: inset 0 0 0 1px hsl(198 78% 37% / 0.3); } 50% { box-shadow: inset 0 0 0 2px hsl(198 78% 37% / 0.6); } } /* Monitoring styles */ .monitoring-cell { display: flex; flex-direction: column; gap: 4px; } .monitor-badge { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 0.75rem; font-weight: 700; text-transform: uppercase; } .monitor-auto { background: hsl(142 60% 45% / 0.2); color: hsl(142 60% 35%); border: 1px solid hsl(142 60% 45% / 0.5); } .monitor-manual { background: hsl(220 13% 80% / 0.2); color: hsl(220 13% 40%); border: 1px solid hsl(220 13% 80% / 0.5); } .scan-mode { font-size: 0.7rem; color: var(--text-muted); text-transform: capitalize; } .next-scan { font-size: 0.7rem; color: hsl(198 78% 37%); } .monitoring-form { display: flex; align-items: center; gap: 8px; margin-top: 4px; } .monitor-toggle { display: flex; align-items: center; gap: 4px; font-size: 0.8rem; cursor: pointer; } .monitor-toggle input[type="checkbox"] { cursor: pointer; } .monitoring-form select { font-size: 0.75rem; padding: 2px 4px; } /* Watcher toggle styles */ .watcher-toggle { background: hsl(45 93% 90% / 0.3); border: 1px solid hsl(45 93% 47% / 0.3); border-radius: 4px; padding: 2px 6px; } .watcher-toggle.active { background: hsl(45 93% 90% / 0.6); border-color: hsl(45 93% 47% / 0.6); } .toggle-hint { margin-left: 4px; cursor: help; } .monitor-options { display: flex; gap: 8px; flex-wrap: wrap; }