/* ============================================ IVY'S RSS HUB — Main Stylesheet Theme: Dark/Light mode with Ivy Green accent ============================================ */ /* === CSS Variables — Dark Theme (Default) === */ :root { /* Colors */ --ivy-green: #10b981; --ivy-green-dark: #059669; --ivy-green-light: #34d399; --bg-primary: #0f0f0f; --bg-secondary: #1a1a1a; --bg-tertiary: #252525; --bg-card: #1e1e1e; --bg-hover: #2a2a2a; --text-primary: #f5f5f5; --text-secondary: #a3a3a3; --text-muted: #737373; --border-color: #333; --border-subtle: #2a2a2a; /* Zebra striping for dark theme */ --zebra-odd: rgba(255, 255, 255, 0.015); /* Category Colors */ --cat-news: #dc2626; --cat-ai: #ec4899; --cat-tech: #3b82f6; --cat-gaming: #8b5cf6; --cat-science: #06b6d4; --cat-apple: #6b7280; --cat-linux: #f59e0b; /* Shadows */ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3); --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4); --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.5); /* Spacing */ --header-height: 60px; --content-max-width: 1400px; --card-gap: 16px; /* Typography */ --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, sans-serif; --font-mono: "SF Mono", Monaco, "Cascadia Code", monospace; /* Transitions */ --transition-fast: 150ms ease; --transition-normal: 250ms ease; /* Border Radius */ --radius-sm: 4px; --radius-md: 8px; --radius-lg: 12px; /* Theme indicator */ --theme-icon: "🌙"; } /* === Light Theme === */ [data-theme="light"] { --bg-primary: #f8fafc; --bg-secondary: #f1f5f9; --bg-tertiary: #e2e8f0; --bg-card: #ffffff; --bg-hover: #e2e8f0; --text-primary: #0f172a; --text-secondary: #475569; --text-muted: #64748b; --border-color: #cbd5e1; --border-subtle: #e2e8f0; /* Lighter shadows for light theme */ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05); --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07); --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1); /* Zebra striping for light theme */ --zebra-odd: rgba(0, 0, 0, 0.02); /* Theme indicator */ --theme-icon: "☀️"; } /* Respect system preference if no manual override */ @media (prefers-color-scheme: light) { :root:not([data-theme="dark"]) { --bg-primary: #f8fafc; --bg-secondary: #f1f5f9; --bg-tertiary: #e2e8f0; --bg-card: #ffffff; --bg-hover: #e2e8f0; --text-primary: #0f172a; --text-secondary: #475569; --text-muted: #64748b; --border-color: #cbd5e1; --border-subtle: #e2e8f0; --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05); --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07); --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1); /* Zebra striping for light theme */ --zebra-odd: rgba(0, 0, 0, 0.02); --theme-icon: "☀️"; } } /* === Reset & Base === */ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } html { scroll-behavior: smooth; } body { font-family: var(--font-sans); background-color: var(--bg-primary); color: var(--text-primary); line-height: 1.6; min-height: 100vh; display: flex; flex-direction: column; } a { color: var(--ivy-green); text-decoration: none; transition: color var(--transition-fast); } a:hover { color: var(--ivy-green-light); } /* === Header === */ .header { position: sticky; top: 0; z-index: 100; background: var(--bg-secondary); border-bottom: 1px solid var(--border-color); height: var(--header-height); } .header-content { max-width: var(--content-max-width); margin: 0 auto; padding: 0 20px; height: 100%; display: flex; align-items: center; gap: 20px; } .logo { display: flex; align-items: center; gap: 8px; font-size: 1.25rem; font-weight: 700; color: var(--text-primary); flex-shrink: 0; } .logo-icon { font-size: 1.5rem; } /* === Navigation Categories === */ .nav-categories { display: flex; gap: 4px; flex-wrap: wrap; flex: 1; justify-content: center; } .nav-btn { background: transparent; border: 1px solid var(--border-color); color: var(--text-secondary); padding: 6px 12px; border-radius: var(--radius-md); cursor: pointer; font-size: 0.875rem; transition: all var(--transition-fast); display: flex; align-items: center; gap: 4px; } .nav-btn:hover { background: var(--bg-hover); color: var(--text-primary); border-color: var(--text-muted); } .nav-btn.active { background: var(--ivy-green); border-color: var(--ivy-green); color: #fff; } /* === Header Actions === */ .header-actions { display: flex; gap: 8px; flex-shrink: 0; } .btn-icon { width: 36px; height: 36px; background: transparent; border: 1px solid var(--border-color); border-radius: var(--radius-md); cursor: pointer; font-size: 1rem; transition: all var(--transition-fast); display: flex; align-items: center; justify-content: center; } .btn-icon:hover { background: var(--bg-hover); border-color: var(--ivy-green); } .btn-icon.spinning { animation: spin 1s linear infinite; } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } /* === Main Content === */ .app-layout { display: flex; flex: 1; max-width: 1600px; margin: 0 auto; width: 100%; gap: 20px; padding: 20px; } .main-content { flex: 1; min-width: 0; } /* === Status Bar === */ .status-bar { display: flex; justify-content: space-between; align-items: center; padding: 8px 12px; background: var(--bg-secondary); border-radius: var(--radius-md); margin-bottom: 20px; font-size: 0.875rem; color: var(--text-secondary); gap: 12px; flex-wrap: wrap; } .status-time { color: var(--text-muted); } /* === Language Filter === */ .lang-filter { display: flex; gap: 4px; } .lang-btn { background: transparent; border: 1px solid var(--border-color); color: var(--text-muted); padding: 4px 10px; border-radius: var(--radius-md); cursor: pointer; font-size: 0.8rem; transition: all var(--transition-fast); } .lang-btn:hover { background: var(--bg-hover); color: var(--text-primary); border-color: var(--text-muted); } .lang-btn.active { background: var(--ivy-green); border-color: var(--ivy-green); color: #fff; } /* === Feeds Container === */ .feeds-container { display: flex; flex-direction: column; gap: 24px; } /* === Source Section === */ .source-section { background: var(--bg-card); border-radius: var(--radius-lg); border: 1px solid var(--border-color); overflow: hidden; } .source-header { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; background: var(--bg-tertiary); border-bottom: 1px solid var(--border-color); cursor: pointer; transition: background var(--transition-fast), box-shadow var(--transition-fast); /* Subtle left border accent - colored per source */ border-left: 3px solid var(--source-accent, var(--ivy-green)); } .source-header:hover { background: var(--bg-hover); } .source-title { display: flex; align-items: center; gap: 10px; font-size: 1rem; font-weight: 600; } .source-icon { font-size: 1.25rem; } .source-name { color: var(--text-primary); } .source-meta { display: flex; align-items: center; gap: 12px; font-size: 0.8rem; color: var(--text-muted); } .source-count { background: var(--source-accent, var(--ivy-green)); color: #fff; padding: 2px 8px; border-radius: 9999px; font-weight: 600; } .source-status { display: flex; align-items: center; gap: 4px; } .source-status.fresh::before { content: ""; width: 6px; height: 6px; background: var(--ivy-green); border-radius: 50%; } .source-status.stale::before { content: ""; width: 6px; height: 6px; background: var(--text-muted); border-radius: 50%; } .source-toggle { font-size: 0.75rem; color: var(--text-muted); transition: transform var(--transition-fast); } .source-section.collapsed .source-toggle { transform: rotate(-90deg); } .source-section.collapsed .source-articles { display: none; } /* === Articles List === */ .source-articles { list-style: none; /* Responsive max-height: min 400px, prefer 50vh, max 1050px */ max-height: clamp(400px, 50vh, 1050px); overflow-y: auto; /* Allow scroll to propagate to parent when reaching bounds */ overscroll-behavior: auto; } .article-item-wrapper { display: flex; align-items: flex-start; border-bottom: 1px solid var(--border-subtle); transition: background var(--transition-fast); } .article-item-wrapper:last-child { border-bottom: none; } /* Subtle zebra striping for better visual distinction */ .article-item-wrapper:nth-child(odd) { background: var(--zebra-odd, rgba(255, 255, 255, 0.015)); } .article-item-wrapper:nth-child(even) { background: transparent; } .article-item-wrapper:hover { background: var(--bg-hover); } .article-item { display: block; flex: 1; padding: 12px 16px; text-decoration: none; color: inherit; } .article-item:hover .article-title { color: var(--ivy-green-light); } .article-title { color: var(--text-primary); font-size: 0.95rem; line-height: 1.4; margin-bottom: 4px; transition: color var(--transition-fast); } .article-item:hover .article-title { color: var(--ivy-green-light); } .article-description { color: var(--text-muted); font-size: 0.8rem; line-height: 1.4; margin-bottom: 6px; display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .article-meta { display: flex; align-items: center; gap: 12px; font-size: 0.8rem; color: var(--text-muted); } .article-date { display: flex; align-items: center; gap: 4px; } .article-source { display: flex; align-items: center; gap: 4px; color: var(--text-muted); font-size: 0.75rem; padding: 2px 6px; background: var(--bg-tertiary); border-radius: var(--radius-sm); } /* === New Article Badge === */ .new-badge { display: inline-block; font-size: 0.6rem; font-weight: 700; padding: 2px 6px; background: var(--ivy-green); color: #fff; border-radius: 4px; text-transform: uppercase; letter-spacing: 0.05em; margin-right: 6px; vertical-align: middle; animation: pulse-badge 2s ease-in-out infinite; } @keyframes pulse-badge { 0%, 100% { opacity: 1; } 50% { opacity: 0.7; } } /* Recent article highlight */ .article-item-wrapper.recent { border-left: 2px solid var(--ivy-green); } .article-item-wrapper.recent .article-date { color: var(--ivy-green); } /* === Loading & Empty States === */ .loading-state, .empty-state, .error-state { text-align: center; padding: 60px 20px; color: var(--text-secondary); } .loading-spinner { width: 40px; height: 40px; border: 3px solid var(--border-color); border-top-color: var(--ivy-green); border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto 16px; } .empty-icon, .error-icon { font-size: 3rem; margin-bottom: 12px; } .loading-state .hint, .empty-state .hint { font-size: 0.8rem; color: var(--text-muted); margin-top: 8px; opacity: 0.8; } /* === Footer === */ .footer { background: var(--bg-secondary); border-top: 1px solid var(--border-color); padding: 16px 20px; text-align: center; font-size: 0.875rem; color: var(--text-secondary); } .footer .divider { margin: 0 8px; color: var(--text-muted); } /* === Modals === */ .modal-overlay { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.8); backdrop-filter: blur(4px); display: flex; align-items: center; justify-content: center; z-index: 1000; opacity: 0; visibility: hidden; transition: all var(--transition-normal); padding: 20px; } .modal-overlay.active { opacity: 1; visibility: visible; } .modal { background: var(--bg-secondary); border-radius: var(--radius-lg); border: 1px solid var(--border-color); padding: 24px; max-width: 500px; width: 100%; max-height: 80vh; overflow-y: auto; position: relative; transform: scale(0.95); transition: transform var(--transition-normal); } .modal-overlay.active .modal { transform: scale(1); } .modal-large { max-width: 700px; } .modal-close { position: absolute; top: 12px; right: 12px; width: 32px; height: 32px; background: transparent; border: 1px solid var(--border-color); border-radius: var(--radius-md); color: var(--text-secondary); font-size: 1.25rem; cursor: pointer; transition: all var(--transition-fast); } .modal-close:hover { background: var(--bg-hover); color: var(--text-primary); border-color: var(--ivy-green); } .modal h2 { margin-bottom: 20px; font-size: 1.5rem; color: var(--ivy-green); } .modal-section { margin-bottom: 20px; } .modal-section h3 { font-size: 1rem; color: var(--text-primary); margin-bottom: 10px; padding-bottom: 6px; border-bottom: 1px solid var(--border-subtle); } .feature-list { list-style: none; } .feature-list li { padding: 4px 0; color: var(--text-secondary); } .ivy-quote { font-style: italic; color: var(--ivy-green); padding: 12px 16px; background: var(--bg-tertiary); border-left: 3px solid var(--ivy-green); border-radius: var(--radius-sm); margin: 20px 0; } .copyright { text-align: center; color: var(--text-muted); font-size: 0.8rem; } /* === Settings Modal Specific === */ .sources-list { display: flex; flex-direction: column; gap: 8px; max-height: 300px; overflow-y: auto; } .source-toggle-item { display: flex; align-items: center; gap: 12px; padding: 10px 12px; background: var(--bg-tertiary); border-radius: var(--radius-md); transition: background var(--transition-fast); } .source-toggle-item:hover { background: var(--bg-hover); } .source-toggle-item input[type="checkbox"] { width: 18px; height: 18px; accent-color: var(--ivy-green); } .source-toggle-info { flex: 1; min-width: 0; /* Allow flex child to shrink below content size */ overflow: hidden; } .source-toggle-name { font-weight: 500; color: var(--text-primary); } .source-toggle-url { font-size: 0.75rem; color: var(--text-muted); /* Prevent long URLs from breaking modal layout */ word-break: break-all; overflow-wrap: anywhere; max-width: 100%; display: block; } .source-toggle-category { font-size: 0.75rem; padding: 2px 8px; background: var(--bg-primary); border-radius: var(--radius-sm); color: var(--text-secondary); } /* Add Feed Form */ .add-feed-form { display: grid; gap: 10px; } .add-feed-form input, .add-feed-form select { padding: 10px 12px; background: var(--bg-tertiary); border: 1px solid var(--border-color); border-radius: var(--radius-md); color: var(--text-primary); font-size: 0.9rem; } .add-feed-form input:focus, .add-feed-form select:focus { outline: none; border-color: var(--ivy-green); } .add-feed-form input::placeholder { color: var(--text-muted); } .btn-primary { background: var(--ivy-green); border: none; color: #fff; padding: 10px 16px; border-radius: var(--radius-md); font-weight: 600; cursor: pointer; transition: background var(--transition-fast); } .btn-primary:hover { background: var(--ivy-green-dark); } .btn-danger { background: #dc2626; border: none; color: #fff; padding: 10px 16px; border-radius: var(--radius-md); font-weight: 600; cursor: pointer; transition: background var(--transition-fast); } .btn-danger:hover { background: #b91c1c; } .reset-section { border-top: 1px solid var(--border-color); padding-top: 16px; margin-top: 8px; } /* Checkbox Labels */ .checkbox-label { display: flex; align-items: center; gap: 10px; padding: 8px 0; color: var(--text-secondary); } .checkbox-label label { cursor: pointer; flex: 1; } .checkbox-label input[type="checkbox"] { width: 18px; height: 18px; accent-color: var(--ivy-green); cursor: pointer; flex-shrink: 0; } .checkbox-label input[type="number"] { width: 60px; padding: 4px 8px; background: var(--bg-tertiary); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-primary); margin-right: 8px; } /* Number input row (for max items) */ .number-input-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 0; color: var(--text-secondary); } .number-input-row label { flex: 1; } .number-input-row input[type="number"] { width: 70px; padding: 6px 10px; background: var(--bg-tertiary); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-primary); text-align: center; } .number-input-row input[type="number"]:focus { outline: none; border-color: var(--ivy-green); } .number-input-row select { padding: 6px 10px; background: var(--bg-tertiary); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-primary); font-size: 0.9rem; cursor: pointer; } .number-input-row select:focus { outline: none; border-color: var(--ivy-green); } .hint { font-size: 0.8rem; color: var(--text-muted); margin-bottom: 12px; } /* Sources Actions (Enable/Disable All) */ .sources-actions { display: flex; gap: 8px; margin-bottom: 12px; } .sources-actions .btn-small { flex: 1; } /* === Scrollbar Styling === */ ::-webkit-scrollbar { width: 8px; height: 8px; } ::-webkit-scrollbar-track { background: var(--bg-primary); } ::-webkit-scrollbar-thumb { background: var(--border-color); border-radius: 4px; } ::-webkit-scrollbar-thumb:hover { background: var(--text-muted); } /* === Responsive Design === */ @media (max-width: 900px) { .header-content { flex-wrap: wrap; height: auto; padding: 12px 16px; gap: 12px; } .nav-categories { order: 3; width: 100%; justify-content: flex-start; overflow-x: auto; flex-wrap: nowrap; padding-bottom: 4px; } .nav-btn { flex-shrink: 0; } .logo-text { font-size: 1.1rem; } } @media (max-width: 600px) { .main-content { padding: 12px; } .source-header { padding: 10px 12px; } .article-item { padding: 10px 12px; } .modal { padding: 16px; } .status-bar { flex-direction: column; gap: 8px; text-align: center; } .status-bar .lang-filter { order: -1; } .status-bar .status-text { font-size: 0.8rem; } } /* ============================================ SIDEBAR STYLES ============================================ */ /* === Sidebar Container === */ .sidebar { width: 320px; flex-shrink: 0; display: flex; flex-direction: column; gap: 16px; position: sticky; top: calc(var(--header-height) + 20px); max-height: calc(100vh - var(--header-height) - 40px); overflow-y: auto; } /* === Sidebar Section === */ .sidebar-section { background: var(--bg-card); border-radius: var(--radius-lg); border: 1px solid var(--border-color); overflow: hidden; } .sidebar-title { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; margin: 0; font-size: 0.9rem; font-weight: 600; color: var(--text-primary); background: var(--bg-tertiary); border-bottom: 1px solid var(--border-color); } .sidebar-title.collapsible { cursor: pointer; transition: background var(--transition-fast); } .sidebar-title.collapsible:hover { background: var(--bg-hover); } .section-toggle { font-size: 0.7rem; color: var(--text-muted); transition: transform var(--transition-fast); } /* Bookmark count badge */ .bookmark-count { font-size: 0.75rem; color: var(--ivy-green); font-weight: 600; margin-left: 4px; } .sidebar-title.collapsed .section-toggle { transform: rotate(-90deg); } .section-content { padding: 12px; max-height: 300px; overflow: hidden; overflow-y: auto; transition: max-height var(--transition-normal), padding var(--transition-normal), opacity var(--transition-normal); } .section-content.collapsed { max-height: 0; padding: 0 12px; overflow: hidden; opacity: 0; } /* === Search Box === */ .search-box { display: flex; gap: 8px; padding: 12px; } .search-box input { flex: 1; padding: 8px 12px; background: var(--bg-tertiary); border: 1px solid var(--border-color); border-radius: var(--radius-md); color: var(--text-primary); font-size: 0.9rem; transition: border-color var(--transition-fast); } .search-box input:focus { outline: none; border-color: var(--ivy-green); } .search-box input::placeholder { color: var(--text-muted); } .search-clear { width: 32px; height: 32px; background: var(--bg-tertiary); border: 1px solid var(--border-color); border-radius: var(--radius-md); color: var(--text-muted); font-size: 1.1rem; cursor: pointer; transition: all var(--transition-fast); display: flex; align-items: center; justify-content: center; } .search-clear:hover { background: var(--bg-hover); color: var(--text-primary); border-color: var(--ivy-green); } .search-results { padding: 0 12px 12px; max-height: 200px; overflow-y: auto; } .search-hint { color: var(--text-muted); font-size: 0.8rem; font-style: italic; } .search-count { font-size: 0.75rem; color: var(--ivy-green); padding: 6px 0; margin-bottom: 6px; border-bottom: 1px solid var(--border-subtle); font-weight: 500; } .search-result-item { display: block; padding: 8px 10px; margin-bottom: 4px; background: var(--bg-tertiary); border-radius: var(--radius-sm); color: var(--text-secondary); font-size: 0.85rem; line-height: 1.3; text-decoration: none; transition: all var(--transition-fast); } .search-result-item:hover { background: var(--bg-hover); color: var(--ivy-green-light); } .search-result-source { font-size: 0.75rem; color: var(--text-muted); margin-top: 2px; } /* Search spinner */ .search-spinner { display: inline-block; width: 12px; height: 12px; border: 2px solid var(--border-color); border-top-color: var(--ivy-green); border-radius: 50%; animation: spin 0.8s linear infinite; margin-right: 6px; vertical-align: middle; } /* === Bookmarks === */ .bookmarks-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; } .bookmark-item { display: flex; align-items: flex-start; gap: 8px; padding: 8px 10px; background: var(--bg-tertiary); border-radius: var(--radius-sm); transition: background var(--transition-fast); } .bookmark-item:hover { background: var(--bg-hover); } .bookmark-link { flex: 1; color: var(--text-secondary); font-size: 0.85rem; line-height: 1.3; text-decoration: none; } .bookmark-link:hover { color: var(--ivy-green-light); } .bookmark-remove { width: 20px; height: 20px; background: transparent; border: none; color: var(--text-muted); font-size: 0.9rem; cursor: pointer; border-radius: var(--radius-sm); transition: all var(--transition-fast); flex-shrink: 0; } .bookmark-remove:hover { background: #ef4444; color: #fff; } .btn-small { width: 100%; padding: 6px 12px; background: var(--bg-tertiary); border: 1px solid var(--border-color); border-radius: var(--radius-md); color: var(--text-muted); font-size: 0.8rem; cursor: pointer; transition: all var(--transition-fast); } .btn-small:hover { background: var(--bg-hover); color: var(--text-primary); border-color: var(--ivy-green); } .empty-hint { color: var(--text-muted); font-size: 0.8rem; font-style: italic; display: block; padding: 8px 0; } /* === Trending Tags === */ .trending-tags { display: flex; flex-wrap: wrap; gap: 6px; } .trending-tag { display: inline-flex; align-items: center; gap: 4px; padding: 4px 10px; background: var(--bg-tertiary); border: 1px solid var(--tag-color, var(--border-color)); border-radius: 9999px; color: var(--tag-color, var(--text-secondary)); font-size: 0.8rem; cursor: pointer; transition: all var(--transition-fast); } /* Trending tag color variations */ .trending-tag:nth-child(12n + 1) { --tag-color: #10b981; } /* Green */ .trending-tag:nth-child(12n + 2) { --tag-color: #3b82f6; } /* Blue */ .trending-tag:nth-child(12n + 3) { --tag-color: #8b5cf6; } /* Purple */ .trending-tag:nth-child(12n + 4) { --tag-color: #ec4899; } /* Pink */ .trending-tag:nth-child(12n + 5) { --tag-color: #f59e0b; } /* Amber */ .trending-tag:nth-child(12n + 6) { --tag-color: #06b6d4; } /* Cyan */ .trending-tag:nth-child(12n + 7) { --tag-color: #84cc16; } /* Lime */ .trending-tag:nth-child(12n + 8) { --tag-color: #f97316; } /* Orange */ .trending-tag:nth-child(12n + 9) { --tag-color: #14b8a6; } /* Teal */ .trending-tag:nth-child(12n + 10) { --tag-color: #a855f7; } /* Violet */ .trending-tag:nth-child(12n + 11) { --tag-color: #ef4444; } /* Red */ .trending-tag:nth-child(12n + 12) { --tag-color: #6366f1; } /* Indigo */ .trending-tag:hover { background: var(--tag-color, var(--ivy-green)); border-color: var(--tag-color, var(--ivy-green)); color: #fff; } .trending-tag:focus { outline: 2px solid var(--tag-color, var(--ivy-green)); outline-offset: 2px; } .trending-tag:focus:not(:focus-visible) { outline: none; } .trending-tag .tag-count { font-size: 0.7rem; padding: 1px 5px; background: rgba(255, 255, 255, 0.15); border-radius: 9999px; } .trending-tag.hot { border-color: #ef4444; color: #ef4444; --tag-color: #ef4444; } .trending-tag.hot:hover { background: #ef4444; color: #fff; } /* === Favorite Sources === */ .favorites-list { display: flex; flex-direction: column; gap: 6px; } .favorite-source { display: flex; align-items: center; gap: 8px; padding: 8px 10px; background: var(--bg-tertiary); border-radius: var(--radius-sm); cursor: pointer; transition: background var(--transition-fast); } .favorite-source:hover { background: var(--bg-hover); } .favorite-icon { font-size: 1rem; } .favorite-name { flex: 1; color: var(--text-secondary); font-size: 0.85rem; } .favorite-count { font-size: 0.75rem; padding: 2px 6px; background: var(--ivy-green); color: #fff; border-radius: 9999px; } .favorite-remove { width: 20px; height: 20px; background: transparent; border: none; color: var(--text-muted); font-size: 0.9rem; cursor: pointer; border-radius: var(--radius-sm); transition: all var(--transition-fast); } .favorite-remove:hover { background: #ef4444; color: #fff; } /* === Calendar === */ .calendar-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; } .calendar-day { display: flex; flex-direction: column; align-items: center; padding: 6px 4px; background: var(--bg-tertiary); border-radius: var(--radius-sm); cursor: pointer; transition: background var(--transition-fast), box-shadow var(--transition-fast), transform var(--transition-fast); min-height: 60px; border: 1px solid transparent; } .calendar-day:hover { background: var(--bg-hover); border-color: var(--border-color); transform: translateY(-1px); } .calendar-day:focus { outline: 2px solid var(--ivy-green); outline-offset: 2px; } .calendar-day:focus:not(:focus-visible) { outline: none; } .calendar-day.active { background: var(--ivy-green); } .calendar-day.active .day-name, .calendar-day.active .day-date, .calendar-day.active .day-count { color: #fff; } .day-name { font-size: 0.65rem; font-weight: 600; color: var(--text-muted); text-transform: uppercase; } .day-date { font-size: 0.95rem; font-weight: 700; color: var(--text-primary); margin: 2px 0; } .day-count { font-size: 0.7rem; font-weight: 600; color: var(--ivy-green); padding: 1px 5px; background: rgba(16, 185, 129, 0.15); border-radius: 9999px; } .day-count.zero { color: var(--text-muted); background: transparent; } /* === Sidebar Toggle (Mobile) === */ .sidebar-toggle { display: none; position: fixed; bottom: 20px; right: 20px; width: 50px; height: 50px; background: var(--ivy-green); border: none; border-radius: 50%; font-size: 1.3rem; cursor: pointer; box-shadow: var(--shadow-lg); z-index: 200; transition: transform var(--transition-fast); } .sidebar-toggle:hover { transform: scale(1.1); } /* === Back to Top Button === */ .back-to-top { position: fixed; bottom: 20px; right: 360px; /* Adjusted: sidebar(320) + gap(20) + button offset(20) */ width: 44px; height: 44px; background: var(--bg-tertiary); border: 1px solid var(--border-color); border-radius: 50%; font-size: 1.2rem; color: var(--text-secondary); cursor: pointer; box-shadow: var(--shadow-md); z-index: 200; opacity: 0; visibility: hidden; transform: translateY(20px); transition: opacity var(--transition-normal), transform var(--transition-normal), background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast); transition-delay: 0s, 0s, 0s, 0s, 0s; will-change: opacity, transform; } /* Adjust position when sidebar is hidden */ .sidebar.hidden-desktop ~ .back-to-top, :has(.sidebar.hidden-desktop) .back-to-top { right: 20px; } .back-to-top.visible { opacity: 1; visibility: visible; transform: translateY(0); transition-delay: 0s; } .back-to-top:hover { background: var(--ivy-green); border-color: var(--ivy-green); color: #fff; transform: translateY(0) scale(1.1); } .back-to-top:focus { outline: 2px solid var(--ivy-green); outline-offset: 2px; } .back-to-top:focus:not(:focus-visible) { outline: none; } /* Position adjustment when keyboard hint is visible */ @media (min-width: 901px) { .back-to-top { bottom: 60px; /* Above keyboard hint */ } } /* Mobile/Tablet: position to not overlap sidebar toggle */ @media (max-width: 1100px) { .back-to-top { right: 80px; /* Left of sidebar toggle */ bottom: 20px; } } /* === Article Bookmark Button === */ .article-bookmark { width: 32px; height: 32px; background: transparent; border: none; color: var(--text-muted); font-size: 1rem; cursor: pointer; border-radius: var(--radius-sm); transition: all var(--transition-fast); flex-shrink: 0; opacity: 0; margin: 10px 8px 0 0; } .article-item-wrapper:hover .article-bookmark { opacity: 1; } .article-bookmark:hover { color: #fbbf24; } .article-bookmark.saved { color: #fbbf24; opacity: 1; } /* === Source Favorite Button === */ .source-favorite { width: 28px; height: 28px; background: transparent; border: 1px solid var(--border-color); color: var(--text-muted); font-size: 0.9rem; cursor: pointer; border-radius: var(--radius-md); transition: all var(--transition-fast); margin-right: 8px; } .source-favorite:hover { border-color: #fbbf24; color: #fbbf24; } .source-favorite.saved { background: #fbbf24; border-color: #fbbf24; color: #1a1a1a; } /* === Responsive Sidebar === */ @media (max-width: 1100px) { .sidebar { position: fixed; top: 0; right: -340px; width: 320px; height: 100vh; max-height: 100vh; padding: 20px 12px 20px; background: var(--bg-secondary); border-left: 1px solid var(--border-color); z-index: 150; transition: right var(--transition-normal); will-change: right; } .sidebar.open { right: 0; } .sidebar-toggle { display: flex; align-items: center; justify-content: center; } .app-layout { padding: 12px; } } @media (max-width: 600px) { .sidebar { width: 100%; right: -100%; } .sidebar.open { right: 0; } } /* ============================================ TOAST NOTIFICATIONS ============================================ */ .toast-notification { position: fixed; bottom: 80px; left: 50%; transform: translateX(-50%) translateY(20px); padding: 12px 24px; background: var(--bg-tertiary); border: 1px solid var(--border-color); border-radius: var(--radius-lg); color: var(--text-primary); font-size: 0.9rem; font-weight: 500; box-shadow: var(--shadow-lg); z-index: 2000; opacity: 0; transition: opacity var(--transition-normal), transform var(--transition-normal); pointer-events: none; will-change: opacity, transform; } .toast-notification.show { opacity: 1; transform: translateX(-50%) translateY(0); } /* Position adjustment on mobile to avoid sidebar toggle */ @media (max-width: 1100px) { .toast-notification { bottom: 100px; } } .toast-success { border-color: var(--ivy-green); background: rgba(16, 185, 129, 0.15); } .toast-error { border-color: #ef4444; background: rgba(239, 68, 68, 0.15); } .toast-info { border-color: #3b82f6; background: rgba(59, 130, 246, 0.15); } /* ============================================ SEARCH HIGHLIGHT ============================================ */ .search-result-item mark { background: rgba(16, 185, 129, 0.3); color: var(--ivy-green-light); padding: 1px 3px; border-radius: 3px; } /* ============================================ KEYBOARD SHORTCUTS HINT ============================================ */ .keyboard-hint { position: fixed; bottom: 20px; left: 20px; padding: 8px 12px; background: var(--bg-tertiary); border: 1px solid var(--border-color); border-radius: var(--radius-md); font-size: 0.75rem; color: var(--text-muted); opacity: 0.7; z-index: 50; transition: opacity var(--transition-fast); } .keyboard-hint:hover { opacity: 1; } .keyboard-hint .divider { margin: 0 6px; opacity: 0.5; } .keyboard-hint kbd { display: inline-block; padding: 2px 6px; background: var(--bg-primary); border: 1px solid var(--border-color); border-radius: 4px; font-family: var(--font-mono); font-size: 0.7rem; color: var(--text-secondary); margin: 0 2px; } @media (max-width: 900px) { .keyboard-hint { display: none; } } /* ============================================ SIDEBAR HIDE TOGGLE (Desktop) ============================================ */ .sidebar.hidden-desktop { display: none; } @media (max-width: 1100px) { .sidebar.hidden-desktop { display: flex; /* On mobile, use the normal toggle behavior */ } } /* ============================================ MOBILE SCROLL INDICATOR FOR CATEGORIES ============================================ */ @media (max-width: 900px) { .nav-categories { position: relative; -webkit-overflow-scrolling: touch; scrollbar-width: none; /* Firefox */ } .nav-categories::-webkit-scrollbar { display: none; } .nav-categories::after { content: ""; position: absolute; right: 0; top: 0; height: 100%; width: 40px; background: linear-gradient(to right, transparent, var(--bg-secondary)); pointer-events: none; } } /* ============================================ SOURCE COLOR VARIATIONS (12 subtle colors) ============================================ */ /* Color palette - subtle variations that work on dark theme */ .source-section[data-color-index="0"] { --source-accent: #10b981; } /* Ivy Green (default) */ .source-section[data-color-index="1"] { --source-accent: #3b82f6; } /* Blue */ .source-section[data-color-index="2"] { --source-accent: #8b5cf6; } /* Purple */ .source-section[data-color-index="3"] { --source-accent: #ec4899; } /* Pink */ .source-section[data-color-index="4"] { --source-accent: #f59e0b; } /* Amber */ .source-section[data-color-index="5"] { --source-accent: #06b6d4; } /* Cyan */ .source-section[data-color-index="6"] { --source-accent: #84cc16; } /* Lime */ .source-section[data-color-index="7"] { --source-accent: #f97316; } /* Orange */ .source-section[data-color-index="8"] { --source-accent: #14b8a6; } /* Teal */ .source-section[data-color-index="9"] { --source-accent: #a855f7; } /* Violet */ .source-section[data-color-index="10"] { --source-accent: #ef4444; } /* Red */ .source-section[data-color-index="11"] { --source-accent: #6366f1; } /* Indigo */ /* ============================================ CACHED STATUS INDICATOR ============================================ */ .source-status.cached::before { content: ""; width: 6px; height: 6px; background: #f59e0b; border-radius: 50%; } /* ============================================ SETTINGS IMPROVEMENTS ============================================ */ /* Add Feed Row (side by side selects) */ .add-feed-row { display: flex; gap: 8px; } .add-feed-row select { flex: 1; } /* Language indicator in sources list */ .source-toggle-lang { font-size: 1rem; flex-shrink: 0; } /* Custom feed badge */ .custom-badge { display: inline-block; font-size: 0.65rem; padding: 2px 6px; background: var(--ivy-green); color: #fff; border-radius: 9999px; text-transform: uppercase; font-weight: 600; letter-spacing: 0.02em; margin-left: 6px; vertical-align: middle; } /* Delete custom feed button */ .source-delete-btn { width: 28px; height: 28px; background: transparent; border: 1px solid transparent; border-radius: var(--radius-md); cursor: pointer; font-size: 0.9rem; opacity: 0.5; transition: all var(--transition-fast); display: flex; align-items: center; justify-content: center; flex-shrink: 0; } .source-delete-btn:hover { opacity: 1; background: rgba(239, 68, 68, 0.15); border-color: #ef4444; } /* Source toggle item improvements */ .source-toggle-item { display: flex; align-items: center; gap: 12px; padding: 10px 12px; background: var(--bg-tertiary); border-radius: var(--radius-md); transition: background var(--transition-fast); } /* ============================================ FAILED FEED INDICATOR ============================================ */ .source-section.error { opacity: 0.6; border-color: #ef4444; } .source-section.error .source-header { border-left-color: #ef4444; } .source-status.error::before { content: ""; width: 6px; height: 6px; background: #ef4444; border-radius: 50%; } /* ============================================ FOCUS STATES FOR ACCESSIBILITY ============================================ */ .source-header:focus { outline: 2px solid var(--ivy-green); outline-offset: 2px; } .source-header:focus:not(:focus-visible) { outline: none; } .source-favorite:focus, .article-bookmark:focus, .nav-btn:focus, .lang-btn:focus { outline: 2px solid var(--ivy-green); outline-offset: 2px; } .source-favorite:focus:not(:focus-visible), .article-bookmark:focus:not(:focus-visible), .nav-btn:focus:not(:focus-visible), .lang-btn:focus:not(:focus-visible) { outline: none; } /* ============================================ LOADING ANIMATION FOR NEW SECTIONS ============================================ */ @keyframes fadeInUp { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .source-section { animation: fadeInUp 0.3s ease-out; animation-fill-mode: backwards; } /* Stagger animation for multiple sources */ .source-section:nth-child(1) { animation-delay: 0ms; } .source-section:nth-child(2) { animation-delay: 50ms; } .source-section:nth-child(3) { animation-delay: 100ms; } .source-section:nth-child(4) { animation-delay: 150ms; } .source-section:nth-child(5) { animation-delay: 200ms; } .source-section:nth-child(6) { animation-delay: 250ms; } .source-section:nth-child(7) { animation-delay: 300ms; } .source-section:nth-child(8) { animation-delay: 350ms; } /* Article items - removed stagger animation for performance with many articles */ /* Only animate first 5 items, rest appear instantly */ .article-item-wrapper:nth-child(-n + 5) { animation: fadeInUp 0.15s ease-out; animation-fill-mode: backwards; } .article-item-wrapper:nth-child(1) { animation-delay: 0ms; } .article-item-wrapper:nth-child(2) { animation-delay: 20ms; } .article-item-wrapper:nth-child(3) { animation-delay: 40ms; } .article-item-wrapper:nth-child(4) { animation-delay: 60ms; } .article-item-wrapper:nth-child(5) { animation-delay: 80ms; } /* ============================================ IMPROVED MOBILE SIDEBAR TOGGLE ============================================ */ .sidebar-toggle:active { transform: scale(0.95); } /* Pulse effect when sidebar has new content */ @keyframes pulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.4); } 50% { box-shadow: 0 0 0 8px rgba(16, 185, 129, 0); } } .sidebar-toggle.has-updates { animation: pulse 2s ease-in-out 3; } /* ============================================ SKIP LINK FOR ACCESSIBILITY ============================================ */ .skip-link { position: absolute; top: -40px; left: 0; background: var(--ivy-green); color: #fff; padding: 8px 16px; z-index: 1001; transition: top 0.3s ease; } .skip-link:focus { top: 0; } /* ============================================ AUTO-REFRESH STATUS INDICATOR ============================================ */ #auto-refresh-status { padding: 8px 12px; background: var(--bg-tertiary); border-radius: var(--radius-md); font-size: 0.85rem; text-align: center; transition: color var(--transition-fast); } #auto-refresh-status:not(:empty) { margin-top: 8px; }