1
Fork 0
mirror of https://github.com/thegeneralist01/archivr synced 2026-10-09 12:55:00 +02:00
archivr/frontend/src/styles.css
TheGeneralist 253f779216 Add YouTube subtitles, local transcription, self-updating yt-dlp/Deno, X Article and thread titles
- Capture YouTube subtitles by default (opt-out in UI, API, CLI --no-subtitles)
- Summarize YouTube videos from subtitles; fetch on demand, then local transcription, then error
- Local transcription fallback: Whisper, Parakeet, Phonon-2 (English only)
- Runtime-resolved, self-updating yt-dlp and Deno JS runtime (fixes YouTube 403s)
- Settings > Instance > yt-dlp: status and in-app update without restart
- X Article titles from article.title, with idempotent startup backfill
- Thread title generation (single and bulk) with per-provider cheap models
- Per-provider title model settings in Settings > Instance
- Docs, mental model, AGENTS.md and transcription spec updated
2026-10-05 19:39:51 +02:00

3464 lines
92 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@500;600&family=Spectral:wght@500;600&display=swap');
:root {
color-scheme: light;
--ink: #20251f;
--muted: #6b6f66;
--muted-2: #8a8d83;
--paper: #f5f0e7;
--paper-2: #e9e1d2;
--paper-3: #fffaf0;
--line: #d2c6b5;
--line-soft: #e5dccd;
--accent: #8d3f30;
--accent-2: #b78342;
--link: #245f72;
--top: #141d18;
--field: #fffdf7;
--r: 3px;
--r2: 6px;
--r3: 10px;
--sans: "Helvetica Neue", Helvetica, Arial, sans-serif;
--serif: "Spectral", Georgia, "Times New Roman", serif;
--display: "Cormorant Garamond", Georgia, serif;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
background: var(--paper);
color: var(--ink);
font-family: var(--sans);
font-size: 14px;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
button,
input,
select {
font: inherit;
}
/* ── Refined scrollbars ──────────────────────────────────────────────────── */
.workspace,
.context-rail {
scrollbar-width: thin;
scrollbar-color: var(--line) transparent;
}
.workspace::-webkit-scrollbar,
.context-rail::-webkit-scrollbar { width: 11px; height: 11px; }
.workspace::-webkit-scrollbar-track,
.context-rail::-webkit-scrollbar-track { background: transparent; }
.workspace::-webkit-scrollbar-thumb,
.context-rail::-webkit-scrollbar-thumb {
background: var(--line);
border-radius: 999px;
border: 3px solid transparent;
background-clip: padding-box;
}
.workspace::-webkit-scrollbar-thumb:hover,
.context-rail::-webkit-scrollbar-thumb:hover {
background: var(--muted-2);
background-clip: padding-box;
border: 3px solid transparent;
}
/* ── Topbar ──────────────────────────────────────────────────────────────── */
.topbar {
height: 58px;
display: grid;
grid-template-columns: auto auto 1fr auto auto;
align-items: center;
gap: 26px;
padding: 0 22px;
background: var(--top);
color: #efe6d6;
border-bottom: 3px solid var(--accent);
}
.brand {
font-family: var(--display);
font-weight: 600;
font-size: 30px;
line-height: 1;
letter-spacing: 0.01em;
color: #f4ead8;
}
/* Archive switcher */
.switcher {
position: relative;
display: inline-flex;
align-items: center;
}
.switcher select {
appearance: none;
-webkit-appearance: none;
border: 1px solid rgba(247, 238, 223, 0.20);
background: rgba(247, 238, 223, 0.06);
color: #f1e8d8;
font-family: var(--sans);
font-weight: 550;
font-size: 13.5px;
letter-spacing: 0.04em;
padding: 8px 32px 8px 15px;
cursor: pointer;
border-radius: 6px;
transition: background .15s ease, border-color .15s ease;
}
.switcher select:hover {
background: rgba(247, 238, 223, 0.11);
border-color: rgba(247, 238, 223, 0.34);
}
.switcher::after {
content: "";
position: absolute;
right: 15px;
top: 50%;
width: 6px; height: 6px;
margin-top: -5px;
border-right: 1.2px solid #b6ab98;
border-bottom: 1.2px solid #b6ab98;
transform: rotate(45deg);
pointer-events: none;
}
/* Groups archive + collection switchers as a single grid item */
.switchers { display: flex; gap: 8px; align-items: center; min-width: 0; }
.nav { display: flex; gap: 22px; justify-content: flex-end; min-width: 0; }
.nav-link {
border: 0;
background: transparent;
color: #cdc1ad;
cursor: pointer;
padding: 6px 0;
font-size: 12.5px;
font-weight: 600;
letter-spacing: 0.1em;
text-transform: uppercase;
position: relative;
}
.nav-link:hover { color: #f4ead8; }
.nav-link.is-active { color: #f4ead8; }
.nav-link.is-active::after {
content: "";
position: absolute;
left: 0; right: 0; bottom: -2px;
height: 1px;
background: var(--accent-2);
}
/* Capture button */
.capture-button {
display: inline-flex;
align-items: center;
gap: 8px;
position: relative;
overflow: hidden;
border: 0;
background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 88%, #fff) 0%, var(--accent) 55%);
color: #f7eddd;
padding: 10px 18px;
cursor: pointer;
font-size: 12px;
font-weight: 600;
letter-spacing: 0.15em;
text-transform: uppercase;
border-radius: var(--r);
box-shadow: inset 0 1px 0 rgba(255, 245, 230, 0.16), 0 1px 2px rgba(20, 29, 24, 0.30);
transition: filter .18s ease, box-shadow .18s ease;
}
.capture-button:hover {
filter: brightness(0.93);
box-shadow: inset 0 1px 0 rgba(255, 245, 230, 0.12), 0 2px 6px rgba(20, 29, 24, 0.34);
}
.capture-button::before {
content: "";
position: absolute;
top: 0; bottom: 0; left: 0;
width: 45%;
background: linear-gradient(100deg, transparent 0%, rgba(255, 246, 232, 0.45) 50%, transparent 100%);
transform: translateX(-180%) skewX(-18deg);
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.capture-button:hover::before { animation: cap-sheen 0.7s ease; }
}
@keyframes cap-sheen {
from { transform: translateX(-180%) skewX(-18deg); }
to { transform: translateX(340%) skewX(-18deg); }
}
/* ── App shell ───────────────────────────────────────────────────────────── */
.app-shell {
height: calc(100vh - 58px);
display: grid;
grid-template-columns: minmax(0, 1fr) 340px;
}
.workspace { min-width: 0; overflow: auto; display: flex; flex-direction: column; }
/* ── View toggle ─────────────────────────────────────────────────────────── */
.view { display: none; }
.view.is-active { display: block; }
/* ── Search toolbar ──────────────────────────────────────────────────────── */
.toolbar {
position: sticky;
top: 0;
z-index: 3;
display: flex;
align-items: center;
gap: 16px;
padding: 12px 22px;
background: color-mix(in srgb, var(--paper) 88%, white);
border-bottom: 1px solid var(--line-soft);
}
.search-field {
position: relative;
flex: 1 1 auto;
min-width: 0;
display: flex;
align-items: center;
height: 42px;
background: var(--field);
border: 1px solid var(--line);
border-radius: 20px;
transition: border-color .15s ease, box-shadow .15s ease;
}
.search-field:focus-within {
border-color: var(--accent);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent);
}
.search-field .ico { display: grid; place-items: center; width: 46px; height: 100%; color: var(--muted-2); flex-shrink: 0; }
.search-field .ico svg { width: 16px; height: 16px; }
.search-input {
flex: 1; min-width: 0; height: 100%;
border: 0; background: transparent; color: var(--ink);
padding: 0 6px 0 0; font-size: 14px; letter-spacing: 0.01em; outline: none;
}
.search-input::placeholder { color: var(--muted-2); }
.search-field .kbd {
margin-right: 12px;
display: inline-flex; align-items: center;
padding: 3px 7px;
font-size: 11px; color: var(--muted);
background: var(--paper-2);
border: 1px solid var(--line-soft);
border-radius: var(--r);
flex-shrink: 0;
}
.result-count {
flex-shrink: 0;
font-size: 13px;
color: var(--muted);
letter-spacing: 0.02em;
white-space: nowrap;
}
.result-count b { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
/* Tag filter badge */
.tag-filter-badge {
display: inline-flex;
align-items: center;
gap: 4px;
background: var(--accent);
color: #fff;
border: 0;
border-radius: var(--r);
font-size: 12px;
padding: 2px 8px;
cursor: pointer;
margin-left: 8px;
}
.tag-filter-badge:hover { opacity: 0.85; }
/* ── Entry table ─────────────────────────────────────────────────────────── */
.entry-table { width: 100%; font-size: 12.5px; }
.entry-header-row {
display: flex;
align-items: stretch;
position: sticky;
top: 67px;
z-index: 2;
background: color-mix(in srgb, var(--paper) 92%, white);
border-bottom: 1px solid var(--line-soft);
color: var(--muted);
font-size: 10.5px;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.entry-header-row > div { padding: 9px 10px; flex-shrink: 0; font-weight: 600; display: flex; align-items: center; }
#entries-body > div {
display: flex;
align-items: center;
cursor: default;
border-bottom: 1px solid var(--line-soft);
}
#entries-body > div > div { padding: 7px 10px; flex-shrink: 0; overflow: hidden; }
/* Pending capture rows (no index class) fall back to nth-child; real rows use explicit classes. */
#entries-body > div:not(.entry-row-outer):nth-child(even) { background: #f2ede5; }
#entries-body > div:not(.entry-row-outer):nth-child(odd) { background: var(--paper-3); }
/* Index-based stripes for real entry rows — immune to pending-capture sibling count. */
#entries-body > .entry-row-outer--light { background: var(--paper-3); }
#entries-body > .entry-row-outer--dark { background: #f2ede5; }
#entries-body > div.is-selected {
background: #eee2d2;
box-shadow: inset 0 0 0 2px var(--accent);
}
#entries-body > div.is-multi-selected {
background: #eee2d2;
box-shadow: inset 0 0 0 2px var(--accent);
}
.col-added { width: 162px; color: var(--muted); }
.col-title { flex: 1 1 0; min-width: 0; overflow: hidden; display: flex; align-items: center; gap: 0.42em; }
.col-type { width: 116px; }
.col-size { width: 100px; display: flex; flex-direction: column; justify-content: center; gap: 1px; }
.size-total { font-variant-numeric: tabular-nums; }
.size-cached-pct {
font-size: 10px;
color: var(--muted);
opacity: 0.8;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.col-url { flex: 0 0 30%; min-width: 0; overflow: hidden; }
/* col-check is first-child but hidden on desktop — target col-added directly */
.entry-header-row .col-added,
#entries-body > div .col-added { padding-left: 22px; }
.entry-header-row > div:last-child,
#entries-body > div > div:last-child { padding-right: 22px; }
.entry-title { color: var(--link); font-weight: 700; min-width: 0; }
.entry-header-row > div { padding: 9px 10px; flex-shrink: 0; font-weight: 600; }
.source-icon { display: flex; align-items: center; justify-content: center; width: 1.05em; height: 1.05em; flex-shrink: 0; }
.source-icon > * { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; }
.source-icon svg { width: 100%; height: 100%; }
.url-cell { color: #555b55; white-space: nowrap; text-overflow: ellipsis; word-break: break-all; }
#entries-body .url-cell:hover { overflow: visible; white-space: normal; }
.type-pill { display: inline-block; padding: 2px 6px; background: #d8e3df; color: #275a5f; border: 1px solid #bfd0ca; border-radius: var(--r); }
/* ── Multi-select checkbox column ───────────────────────────────────────── */
/* Hidden on desktop (pointer:fine); always visible on touch/mobile */
.col-check {
display: none;
width: 40px;
flex-shrink: 0;
align-items: center;
justify-content: center;
padding: 0 !important;
cursor: pointer;
}
.row-checkbox {
/* reset <button> UA styles */
-webkit-appearance: none;
appearance: none;
padding: 0;
border: 1.5px solid var(--line);
cursor: pointer;
/* visual checkbox */
display: block;
width: 17px;
height: 17px;
border-radius: 4px;
background: var(--paper-3);
transition: border-color .15s ease, background .15s ease;
position: relative;
flex-shrink: 0;
}
.row-checkbox.is-checked {
background: var(--accent);
border-color: var(--accent);
}
.row-checkbox.is-checked::after {
content: '';
position: absolute;
left: 4px;
top: 2px;
width: 5px;
height: 8px;
border: 2px solid #fff;
border-top: none;
border-left: none;
transform: rotate(45deg);
}
@media (pointer: coarse) {
.col-check { display: flex; }
.entry-header-row .col-added,
#entries-body > div .col-added { padding-left: 10px; }
}
/* ── Runs view (table) ───────────────────────────────────────────────────── */
#runs-view .entry-table {
border-collapse: collapse;
table-layout: auto;
}
#runs-view .entry-table th {
position: sticky;
top: 0;
z-index: 1;
text-align: left;
padding: 10px;
background: color-mix(in srgb, var(--paper) 92%, white);
color: var(--muted);
border-bottom: 1px solid var(--line-soft);
font-size: 10.5px;
text-transform: uppercase;
letter-spacing: 0.08em;
}
#runs-view .entry-table td {
padding: 10px;
border-bottom: 1px solid var(--line-soft);
vertical-align: top;
}
#runs-view .entry-table tr:nth-child(even) td { background: #f2ede5; }
#runs-view .entry-table tr:nth-child(odd) td { background: var(--paper-3); }
/* ── Context rail ────────────────────────────────────────────────────────── */
.context-rail {
border-left: 1px solid var(--line);
background: var(--paper);
padding: 20px 20px 32px;
overflow: auto;
}
.rail-eyebrow {
font-size: 10.5px;
font-weight: 600;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--muted-2);
margin-bottom: 16px;
}
.rail-title {
display: block;
font-family: var(--sans);
font-weight: 700;
font-size: 15.5px;
line-height: 1.4;
color: var(--ink);
margin: 0 0 16px;
word-break: break-word;
}
/* original-url tile */
.url-tile {
display: flex;
align-items: center;
gap: 9px;
padding: 10px 12px;
background: var(--paper-3);
border: 1px solid var(--line);
border-radius: var(--r3);
margin-bottom: 20px;
text-decoration: none;
}
.url-tile:hover { background: var(--field); border-color: var(--accent); }
.url-tile .ico { color: var(--ink); flex-shrink: 0; display: grid; place-items: center; }
.url-tile .ico svg { width: 15px; height: 15px; }
.url-tile .u-text {
min-width: 0; flex: 1;
font-size: 12.5px; color: var(--link);
font-family: ui-monospace, "SF Mono", Menlo, monospace;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.url-tile .ext { color: var(--muted-2); flex-shrink: 0; }
.url-tile .ext svg { width: 13px; height: 13px; display: block; }
/* metadata ledger */
.meta-list { margin-bottom: 24px; border-top: 1px solid var(--line-soft); }
.meta-item {
display: grid;
grid-template-columns: 92px 1fr;
gap: 14px;
align-items: baseline;
padding: 9px 0;
border-bottom: 1px solid var(--line-soft);
}
.meta-k {
font-size: 10.5px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--muted-2);
}
.meta-v { font-size: 13.5px; color: var(--ink); word-break: break-word; line-height: 1.4; }
.meta-v.mono { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 12px; color: var(--muted); }
.rail-section { margin-bottom: 24px; }
.rail-section-heading {
display: flex; align-items: baseline; gap: 8px;
font-size: 10.5px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--muted-2);
margin-bottom: 9px;
padding-bottom: 8px;
border-bottom: 1px solid var(--line);
}
.rail-section-heading .num { color: var(--muted-2); font-weight: 600; }
/* artifacts */
.artifact-list { list-style: none; margin: 0; padding: 0; }
.artifact-link {
display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
padding: 7px 2px;
border-bottom: 1px solid var(--line-soft);
text-decoration: none;
}
.artifact-link:last-child { border-bottom: 0; }
.artifact-name { font-size: 13px; color: var(--link); min-width: 0; word-break: break-word; }
.artifact-link:hover .artifact-name { text-decoration: underline; }
.artifact-size { font-size: 11.5px; color: var(--muted-2); flex-shrink: 0; font-variant-numeric: tabular-nums; }
.artifact-group { list-style: none; }
.artifact-group-header {
width: 100%; background: none; border: none; border-bottom: 1px solid var(--line-soft);
cursor: pointer; text-align: left; color: inherit; font: inherit;
}
.artifact-group-header:hover .artifact-name { text-decoration: underline; }
.artifact-group-chevron {
display: inline-block;
font-style: normal;
transition: transform 0.15s ease;
transform: rotate(0deg);
transform-origin: 45% 50%;
margin-right: 3px;
}
.artifact-group-chevron.open { transform: rotate(90deg); }
.artifact-group-body { padding-left: 14px; }
/* tags */
.tags-wrap { display: flex; flex-wrap: wrap; gap: 7px; margin: 0 0 12px; }
.tag-pill {
display: inline-flex; align-items: center; gap: 7px;
background: var(--paper-2);
border: 1px solid var(--line);
border-radius: var(--r);
font-size: 12px; padding: 4px 7px 4px 10px;
color: var(--ink);
}
.tag-pill .remove {
border: 0; background: transparent; cursor: pointer;
color: var(--muted-2); width: 15px; height: 15px;
display: grid; place-items: center; font-size: 13px; line-height: 1;
}
.tag-pill .remove:hover { color: var(--accent); }
.tags-empty { font-size: 13px; color: var(--muted); margin: 0 0 11px; }
.tag-input-wrap {
display: flex; align-items: center; gap: 8px;
background: var(--field);
border: 1px solid var(--line);
border-radius: var(--r2);
padding: 2px 2px 2px 11px;
transition: border-color .15s ease, box-shadow .15s ease;
}
.tag-input-wrap:focus-within {
border-color: var(--accent);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 12%, transparent);
}
.tag-input-wrap .hash { color: var(--muted-2); font-size: 13px; }
.tag-input {
flex: 1; min-width: 0; border: 0; background: transparent;
color: var(--ink); font-size: 13px; padding: 6px 0; outline: none;
font-family: ui-monospace, "SF Mono", Menlo, monospace;
}
.tag-add-btn {
border: 0; background: var(--ink); color: var(--paper-3);
padding: 6px 13px; font-size: 11.5px; letter-spacing: 0.06em;
text-transform: uppercase; border-radius: var(--r);
cursor: pointer; white-space: nowrap;
}
.tag-add-btn:hover { background: #2c332b; }
/* collections in rail */
.coll-row {
display: flex; align-items: center; justify-content: space-between; gap: 12px; overflow: hidden;
padding: 9px 13px;
background: var(--field);
border: 1px solid var(--line);
border-radius: var(--r2);
margin-bottom: 6px;
transition: border-color .15s ease;
}
.coll-row:hover { border-color: var(--accent); }
.coll-name { font-size: 13px; color: var(--ink); font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.vis-badge {
display: inline-flex; align-items: center; gap: 6px;
font-size: 11px; color: var(--muted);
background: var(--paper-2); border: 1px solid var(--line-soft);
border-radius: 999px; padding: 3px 10px;
}
.vis-badge::before {
content: ""; width: 6px; height: 6px; border-radius: 50%;
background: var(--accent-2);
}
/* ── Bulk-action panel ───────────────────────────────────────────────────── */
.bulk-panel { padding-top: 2px; }
.bulk-count {
font-size: 13px;
color: var(--muted);
margin-bottom: 22px;
}
.bulk-count-num {
font-size: 22px;
font-weight: 700;
color: var(--ink);
line-height: 1;
margin-right: 4px;
}
.bulk-coll-row {
display: flex;
align-items: center;
gap: 8px;
}
.bulk-coll-select {
flex: 1;
min-width: 0;
height: 32px;
padding: 0 8px;
border: 1px solid var(--line);
border-radius: var(--r);
background: var(--field);
color: var(--ink);
font-size: 13px;
cursor: pointer;
outline: none;
transition: border-color .15s ease;
}
.bulk-coll-select:focus { border-color: var(--accent); }
.tag-add-btn:disabled { opacity: 0.45; cursor: default; }
.bulk-title-note { font-size: 12px; color: var(--muted); margin: 6px 0 0; }
.bulk-title-note.form-msg--ok { color: var(--link); }
.bulk-title-note.form-msg--err { color: var(--accent); }
/* ── Rail delete zone ───────────────────────────────────────────────────── */
.rail-delete-zone {
margin-top: 24px;
padding-top: 20px;
border-top: 1px solid var(--line-soft);
}
.rail-delete-btn {
width: 100%;
padding: 8px 14px;
background: none;
border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
color: var(--accent);
border-radius: var(--r);
cursor: pointer;
font-size: 12.5px;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
transition: background 0.15s ease, border-color 0.15s ease;
}
.rail-delete-btn:hover {
background: color-mix(in srgb, var(--accent) 8%, transparent);
border-color: var(--accent);
}
.rail-rearchive-btn {
width: 100%;
padding: 6px 12px;
background: var(--surface-2, #2a2a2a);
color: var(--text, #e0e0e0);
border: 1px solid var(--border, #444);
border-radius: 4px;
cursor: pointer;
font-size: 13px;
}
.rail-rearchive-btn:hover:not(:disabled) {
background: var(--surface-3, #333);
}
.rail-rearchive-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
/* ── Capture dialog ──────────────────────────────────────────────────────── */
.capture-dialog {
border: 1px solid var(--line);
background: var(--paper);
padding: 0;
width: min(540px, calc(100vw - 32px));
border-radius: var(--r3);
box-shadow: 0 20px 60px rgba(20, 29, 24, 0.28);
}
.capture-dialog::backdrop {
background: rgba(20, 29, 24, 0.45);
}
.capture-dialog-inner {
padding: 28px;
}
.capture-dialog-title {
margin: 0;
font-size: 22px;
font-family: var(--display);
font-weight: 600;
}
.capture-label {
display: block;
font-size: 11px;
font-weight: 600;
margin-bottom: 6px;
color: var(--muted-2);
text-transform: uppercase;
letter-spacing: 0.06em;
}
.capture-input {
width: 100%;
height: 44px;
border: 1px solid var(--line);
background: var(--field);
color: var(--ink);
padding: 0 14px;
font-size: 15px;
margin-bottom: 10px;
border-radius: var(--r2);
outline: none;
transition: border-color .15s ease, box-shadow .15s ease;
}
.capture-input:focus {
border-color: var(--accent);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent);
}
.form-field .capture-input { margin-bottom: 0; }
.capture-error {
color: var(--accent);
font-size: 13px;
margin-bottom: 10px;
min-height: 18px;
}
.capture-actions {
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 18px;
}
.capture-submit {
border: 0;
background: var(--ink);
color: var(--paper);
padding: 13px 20px;
border-radius: var(--r2);
cursor: pointer;
font-weight: 600;
font-size: 15px;
width: 100%;
min-width: 220px;
letter-spacing: 0.01em;
}
.capture-submit:hover { opacity: 0.85; }
.capture-submit:disabled { opacity: 0.45; cursor: default; }
.capture-cancel {
border: 0;
background: none;
color: var(--muted);
padding: 7px 18px;
border-radius: var(--r);
cursor: pointer;
font-size: 13px;
text-align: center;
width: 100%;
}
.capture-cancel:hover { color: var(--ink); background: var(--paper-2); }
/* ── Capture advanced options ────────────────────────────────────────────── */
.capture-advanced { margin-top: 12px; }
.capture-advanced-toggle {
display: flex;
align-items: center;
gap: 5px;
background: none;
border: 0;
cursor: pointer;
color: var(--muted);
font-size: 12.5px;
padding: 4px 0;
border-radius: var(--r);
}
.capture-advanced-toggle:hover { color: var(--ink); }
.capture-chevron {
width: 14px; height: 14px;
flex-shrink: 0;
transition: transform 0.18s ease;
}
.capture-chevron--open { transform: rotate(180deg); }
.capture-advanced-panel {
margin-top: 8px;
padding: 10px 12px;
border: 1px solid var(--line);
border-radius: var(--r2);
background: var(--paper-2);
}
.capture-ext-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
cursor: default;
}
.capture-ext-label { flex: 1; min-width: 0; }
.capture-ext-name {
display: block;
font-size: 13px;
font-weight: 600;
color: var(--ink);
}
.capture-ext-desc {
display: block;
font-size: 11.5px;
color: var(--muted);
margin-top: 1px;
}
/* ── Capture dialog: header + multi-row ─────────────────────────────────── */
.capture-dialog-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
}
.capture-dialog-close {
flex-shrink: 0;
background: none;
border: 0;
cursor: pointer;
color: var(--muted);
width: 28px;
height: 28px;
display: grid;
place-items: center;
border-radius: var(--r);
padding: 0;
}
.capture-dialog-close svg { width: 14px; height: 14px; }
.capture-dialog-close:hover { background: var(--paper-2); color: var(--ink); }
.capture-rows {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 8px;
}
.capture-row {
display: flex;
flex-direction: column;
gap: 3px;
}
.capture-row-main {
display: flex;
align-items: center;
gap: 8px;
}
/* No bottom-margin on inputs inside rows; gap handles spacing */
.capture-row-main .capture-input { margin-bottom: 0; }
/* Quality selector shown for yt-dlp sources */
.capture-quality {
flex-shrink: 0;
height: 32px;
padding: 0 6px;
border: 1px solid var(--line);
border-radius: var(--r);
background: var(--paper);
color: var(--ink);
font-size: 12px;
cursor: pointer;
outline: none;
transition: border-color .15s;
}
.capture-quality:hover { border-color: var(--accent-2); }
.capture-quality:focus { border-color: var(--accent); }
.capture-quality:disabled { opacity: 0.5; cursor: default; }
/* Probing state: ellipsis shown while yt-dlp metadata is in flight */
.capture-quality-probing {
flex-shrink: 0;
font-size: 12px;
color: var(--muted);
padding: 0 4px;
letter-spacing: .05em;
}
/* "No video detected" note */
.capture-quality-hint {
flex-shrink: 0;
font-size: 12px;
color: var(--muted);
font-style: italic;
}
.capture-quality-hint--error { color: #c05000; font-style: normal; }
/* Status dot */
.cap-dot {
flex-shrink: 0;
width: 20px;
height: 20px;
border-radius: 50%;
display: grid;
place-items: center;
font-size: 10px;
font-weight: 700;
line-height: 1;
}
.cap-dot--idle { background: var(--paper-2); }
.cap-dot--running { background: #fdefd8; color: #8a4f10; }
.cap-dot--ok { background: #d8eddf; color: #235c35; }
.cap-dot--err { background: #f5ddd8; color: #8d3f30; }
/* Spinner inside the running dot */
.cap-spinner {
display: block;
width: 10px;
height: 10px;
border: 2px solid currentColor;
border-top-color: transparent;
border-radius: 50%;
animation: cap-spin 0.7s linear infinite;
}
@keyframes cap-spin { to { transform: rotate(360deg); } }
/* Per-row action buttons (remove / retry) */
.capture-row-action {
flex-shrink: 0;
background: none;
border: 0;
cursor: pointer;
color: var(--muted);
width: 28px;
height: 28px;
display: grid;
place-items: center;
border-radius: var(--r);
padding: 0;
}
.capture-row-action svg { width: 12px; height: 12px; }
.capture-row-action:hover { color: var(--accent); background: var(--paper-2); }
.capture-row-remove:hover { color: var(--accent); }
/* Inline error under a failed row */
.capture-row-error {
margin: 0;
padding-left: 28px; /* align past the status dot */
font-size: 12px;
color: var(--accent);
line-height: 1.45;
}
/* ── Text-capture row ───────────────────────────────────────────────────
A text row breaks the [dot][one-line-input][×] shape used by URL and
file rows: it stacks a title, a multi-line body, and a small footer
(mime selector). Everything lives inside .capture-text-inputs so the
outer flex-row still gives us [icon][content][×] alignment. */
.capture-text-row > .capture-row-main {
/* Icon and remove button sit at the top of the block, not centered on
the tall textarea. */
align-items: flex-start;
}
.capture-text-icon {
flex-shrink: 0;
width: 20px;
height: 44px; /* matches .capture-text-title height */
display: grid;
place-items: center;
color: var(--muted);
}
.capture-text-inputs {
flex: 1 1 auto;
min-width: 0; /* let the textarea shrink inside flex */
display: flex;
flex-direction: column;
gap: 8px;
}
.capture-text-input {
width: 100%;
border: 1px solid var(--line);
background: var(--field);
color: var(--ink);
border-radius: var(--r2);
outline: none;
transition: border-color .15s ease, box-shadow .15s ease;
font-family: inherit;
}
.capture-text-input:focus {
border-color: var(--accent);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent);
}
.capture-text-title {
height: 44px;
padding: 0 14px;
font-size: 15px;
}
.capture-text-body {
min-height: 140px;
padding: 10px 14px;
font-size: 14px;
line-height: 1.55;
resize: vertical;
}
.capture-text-body::placeholder,
.capture-text-title::placeholder {
color: var(--muted);
}
.capture-text-footer {
display: flex;
align-items: center;
gap: 8px;
justify-content: flex-end; /* mime selector sits under the body */
}
/* Mime selector: reuse the small chip styling of .capture-quality. */
.capture-text-mime {
flex-shrink: 0;
height: 28px;
padding: 0 26px 0 10px;
border: 1px solid var(--line);
border-radius: var(--r);
background: var(--paper);
color: var(--ink);
font-size: 12px;
cursor: pointer;
outline: none;
transition: border-color .15s;
/* Custom caret so it doesn't look like an unstyled OS dropdown. */
appearance: none;
-webkit-appearance: none;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none' stroke='%23888' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'><path d='M3 4.5l3 3 3-3'/></svg>");
background-repeat: no-repeat;
background-position: right 8px center;
}
.capture-text-mime:hover { border-color: var(--accent-2); }
.capture-text-mime:focus { border-color: var(--accent); }
/* Remove button on text row: pin to top so tall bodies don't push it. */
.capture-text-row .capture-row-action {
margin-top: 8px;
}
/* Add-another button */
.capture-add-row {
display: flex;
align-items: center;
gap: 7px;
width: 100%;
background: none;
border: 1px dashed var(--line);
border-radius: var(--r);
color: var(--muted);
font-size: 13px;
cursor: pointer;
padding: 7px 12px;
margin-top: 4px;
margin-bottom: 18px;
transition: border-color .15s, color .15s, background .15s;
}
.capture-add-row svg { width: 13px; height: 13px; flex-shrink: 0; }
.capture-add-row:hover { border-color: var(--accent-2); color: var(--ink); background: var(--paper-2); }
/* Upload file button group (Add URL + Upload file side by side) */
.capture-add-row-group {
display: flex;
gap: 8px;
margin-top: 4px;
margin-bottom: 18px;
}
.capture-add-row-group .capture-add-row {
margin-top: 0;
margin-bottom: 0;
flex: 1;
}
/* Drag-over state on the whole dialog */
.capture-dialog--dragover .capture-dialog-inner {
outline: 2px dashed var(--accent);
outline-offset: -6px;
border-radius: var(--r3);
}
/* File row */
.capture-file-icon {
flex-shrink: 0;
color: var(--muted);
display: flex;
align-items: center;
}
.capture-file-name {
flex: 1;
min-width: 0;
font-size: 13.5px;
color: var(--ink);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.capture-file-name--error { color: var(--accent); }
/* Upload progress bar */
.capture-file-progress-wrap {
flex-shrink: 0;
display: flex;
align-items: center;
gap: 6px;
}
.capture-file-progress-bar {
width: 80px;
height: 4px;
border-radius: 2px;
background: var(--paper-2);
overflow: hidden;
border: 1px solid var(--line);
}
.capture-file-progress-fill {
display: block;
height: 100%;
background: var(--ink);
border-radius: 2px;
transition: width 0.1s ease;
}
.capture-file-progress-pct {
font-size: 11px;
color: var(--muted);
min-width: 28px;
text-align: right;
}
/* Done / error badge */
.capture-file-badge {
flex-shrink: 0;
width: 18px;
height: 18px;
border-radius: 50%;
display: grid;
place-items: center;
font-size: 11px;
font-weight: 700;
line-height: 1;
}
.capture-file-badge--done {
background: #d8eddf;
color: #235c35;
}
.capture-file-badge--error {
background: #f5ddd8;
color: #8d3f30;
}
/* ── Toast stack ─────────────────────────────────────────────────────────── */
.toast-stack {
position: fixed;
bottom: 24px;
right: 24px;
z-index: 9000;
display: flex;
flex-direction: column;
gap: 10px;
width: 340px;
max-width: calc(100vw - 32px);
pointer-events: none;
}
.toast {
pointer-events: auto;
background: var(--paper);
border: 1px solid var(--line);
border-radius: var(--r2);
box-shadow: 0 6px 24px rgba(20, 29, 24, 0.18), 0 1px 4px rgba(20, 29, 24, 0.1);
overflow: hidden;
animation: toast-slide-in 0.22s cubic-bezier(.22,.68,0,1.2);
}
@keyframes toast-slide-in {
from { opacity: 0; transform: translateY(10px) scale(0.97); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
.toast--error { border-left: 3px solid var(--accent); }
.toast--warning { border-left: 3px solid #e8a000; }
.toast--success { border-left: 3px solid #22a855; }
.toast-top {
display: flex;
align-items: flex-start;
gap: 10px;
padding: 12px 12px 12px 14px;
}
.toast-icon {
flex-shrink: 0;
font-size: 13px;
font-weight: 700;
color: var(--accent);
margin-top: 2px;
}
.toast--success .toast-icon { color: #22a855; }
.toast--warning .toast-icon { color: #e8a000; }
.toast-body {
flex: 1;
min-width: 0;
}
.toast-headline {
display: block;
font-size: 13.5px;
font-weight: 600;
color: var(--ink);
line-height: 1.3;
}
.toast-locator {
display: block;
font-size: 12px;
color: var(--muted);
margin-top: 2px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.toast-btns {
display: flex;
align-items: center;
gap: 6px;
flex-shrink: 0;
}
.toast-view-btn {
background: none;
border: 1px solid var(--line);
color: var(--link);
font-size: 12px;
cursor: pointer;
padding: 3px 9px;
border-radius: var(--r);
white-space: nowrap;
}
.toast-view-btn:hover { background: var(--paper-2); border-color: var(--link); }
.toast-dismiss {
background: none;
border: 0;
cursor: pointer;
color: var(--muted);
font-size: 20px;
line-height: 1;
width: 24px;
height: 24px;
display: grid;
place-items: center;
border-radius: var(--r);
padding: 0;
}
.toast-dismiss:hover { color: var(--ink); background: var(--paper-2); }
.toast-error-detail {
margin: 0;
padding: 10px 14px 12px;
font-family: ui-monospace, "SF Mono", Menlo, monospace;
font-size: 11.5px;
line-height: 1.55;
color: var(--muted);
background: var(--paper-2);
border-top: 1px solid var(--line);
white-space: pre-wrap;
word-break: break-word;
max-height: 200px;
overflow-y: auto;
}
.toast-warning-detail {
margin: 0;
padding: 10px 14px 12px;
font-size: 12px;
line-height: 1.55;
color: var(--muted);
background: var(--paper-2);
border-top: 1px solid var(--line);
white-space: pre-wrap;
word-break: break-word;
}
.toast-ignore-btn { color: var(--muted); }
/* ── Extension toggle (pill switch) ─────────────────────────────────────── */
.ext-toggle {
flex-shrink: 0;
position: relative;
width: 44px;
height: 24px;
border-radius: 12px;
background: var(--line);
border: 0;
cursor: pointer;
transition: background 0.18s ease;
padding: 0;
}
.ext-toggle--sm { width: 36px; height: 20px; border-radius: 10px; }
.ext-toggle--on { background: var(--ink); }
.ext-toggle:disabled { opacity: 0.4; cursor: default; }
.ext-toggle-knob {
position: absolute;
top: 3px; left: 3px;
width: 18px; height: 18px;
border-radius: 50%;
background: var(--paper);
transition: transform 0.18s ease;
display: block;
box-shadow: 0 1px 3px rgba(0,0,0,.2);
}
.ext-toggle--sm .ext-toggle-knob { width: 14px; height: 14px; top: 3px; left: 3px; }
.ext-toggle--on .ext-toggle-knob { transform: translateX(20px); }
.ext-toggle--sm.ext-toggle--on .ext-toggle-knob { transform: translateX(16px); }
/* ── Extension card (Settings / Extensions tab) ──────────────────────────── */
.ext-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
gap: 12px;
}
.ext-card {
border: 1px solid var(--line);
border-radius: var(--r2);
padding: 16px 18px;
background: var(--paper);
}
.ext-card-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
}
.ext-card-info { flex: 1; min-width: 0; }
.ext-card-name {
display: block;
font-weight: 600;
font-size: 14px;
margin-bottom: 4px;
}
.ext-card-desc {
display: block;
font-size: 13px;
color: var(--muted);
line-height: 1.5;
}
.ext-card-hint {
display: block;
font-size: 12px;
color: #e8a000;
margin-top: 6px;
}
.ext-card-hint code { font-size: 11.5px; }
.form-hint { font-size: 13px; color: var(--muted); line-height: 1.55; margin: 0; }
/* ── Utility ─────────────────────────────────────────────────────────────── */
.muted { color: var(--muted); }
/* ── Admin view ──────────────────────────────────────────────────────────── */
.admin-view {
padding: 22px;
}
.admin-list {
display: grid;
gap: 10px;
max-width: 780px;
}
.admin-archive {
border: 1px solid var(--line);
background: var(--paper-3);
padding: 12px;
border-radius: var(--r2);
}
/* ── Tag tree ────────────────────────────────────────────────────────────── */
.tag-tree {
padding: 20px 22px;
max-width: 320px;
}
.tag-tree-header {
display: flex;
align-items: baseline;
gap: 10px;
margin-bottom: 14px;
border-bottom: 1px solid var(--line-soft);
padding-bottom: 10px;
}
.tag-tree-title {
font-size: 11px;
font-weight: 700;
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.07em;
}
.tag-tree-active {
font-size: 12px;
color: var(--muted-2);
font-style: italic;
}
.tag-tree-list {
list-style: none;
margin: 0;
padding: 0;
}
.tag-children {
padding-left: 16px;
}
.tag-node-btn {
border: 0;
background: transparent;
color: var(--link);
cursor: pointer;
padding: 3px 0;
text-align: left;
font-size: 13px;
display: block;
width: 100%;
}
.tag-node-btn:hover { text-decoration: underline; }
.tag-node-btn.is-active { font-weight: 600; color: var(--ink); }
/* tag-node-row: flex row containing the name button + delete × */
.tag-node-row {
display: flex;
align-items: center;
gap: 4px;
}
.tag-node-row .tag-node-btn {
flex: 1 1 0;
min-width: 0;
display: flex;
align-items: center;
gap: 4px;
width: auto;
}
/* constrain the edit pencil so it doesn't inherit unconstrained SVG dimensions */
.tag-node-btn .edit-icon {
width: 0.75em;
height: 0.75em;
flex-shrink: 0;
vertical-align: -0.1em;
opacity: 0.35;
}
.tag-node-btn:hover .edit-icon { opacity: 0.65; }
/* delete × button next to tag name — small, unobtrusive */
.tag-node-delete {
flex-shrink: 0;
border: 0;
background: transparent;
color: var(--muted-2);
cursor: pointer;
padding: 0 3px;
font-size: 14px;
line-height: 1;
opacity: 0;
}
.tag-node-row:hover .tag-node-delete { opacity: 1; }
.tag-node-delete:hover { color: var(--accent); }
/* rename input inside the tag list */
.tag-rename-input {
font-size: 13px;
flex: 1 1 0;
min-width: 0;
padding: 2px 5px;
border: 1px solid var(--accent);
border-radius: var(--r);
background: var(--field);
color: var(--ink);
outline: none;
}
/* entry count badge next to tag name */
.tag-node-label { flex-shrink: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tag-node-count {
font-size: 11px;
color: var(--muted-2);
font-weight: 400;
flex-shrink: 0;
margin-left: 3px;
}
/* header action buttons (+ New, Move) */
.tag-tree-header { align-items: center; }
.tag-tree-actions { margin-left: auto; display: flex; gap: 4px; }
.tag-tree-action-btn {
font-size: 11px;
padding: 2px 7px;
border: 1px solid var(--line);
border-radius: var(--r);
background: transparent;
color: var(--muted);
cursor: pointer;
line-height: 1.5;
white-space: nowrap;
transition: background 0.1s, color 0.1s;
}
.tag-tree-action-btn:hover:not(:disabled) { background: var(--paper-2); color: var(--ink); }
.tag-tree-action-btn:disabled { opacity: 0.4; cursor: default; }
.tag-tree-action-btn--cancel { border-color: var(--accent); color: var(--accent); }
.tag-tree-action-btn--cancel:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); }
.tag-tree-title--move { font-style: italic; color: var(--accent-2); }
/* move source-select mode: nodes act as clickable targets */
.tag-node-row--move-select .tag-node-btn { cursor: crosshair; color: var(--ink); }
.tag-node-row--move-select .tag-node-btn:hover {
background: color-mix(in srgb, var(--link) 10%, transparent);
text-decoration: none;
border-radius: var(--r);
}
/* ── Tag picker modal (create/move destination) ──────────────────────────── */
.tag-picker-backdrop {
position: fixed;
inset: 0;
z-index: 200;
background: rgba(0, 0, 0, 0.45);
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.tag-picker-modal {
background: var(--paper);
border-radius: var(--r3);
box-shadow: 0 16px 56px rgba(0, 0, 0, 0.24);
width: 300px;
max-width: 100%;
display: flex;
flex-direction: column;
max-height: 60vh;
}
.tag-picker-header {
display: flex;
align-items: center;
padding: 12px 14px;
border-bottom: 1px solid var(--line);
flex-shrink: 0;
gap: 8px;
}
.tag-picker-title {
flex: 1;
font-size: 13px;
font-weight: 600;
color: var(--ink);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.tag-picker-close {
width: 26px;
height: 26px;
border-radius: 50%;
border: none;
background: transparent;
color: var(--muted-2);
font-size: 18px;
line-height: 1;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.tag-picker-close:hover { background: var(--paper-2); color: var(--ink); }
.tag-picker-body {
flex: 1;
min-height: 0;
overflow-y: auto;
padding: 8px 12px 12px;
}
.tag-picker-root-btn {
display: block;
width: 100%;
text-align: left;
padding: 5px 8px;
margin-bottom: 6px;
border: 1px dashed var(--line);
border-radius: var(--r);
background: transparent;
color: var(--muted);
font-size: 12px;
cursor: pointer;
}
.tag-picker-root-btn:hover { background: var(--paper-2); color: var(--ink); border-color: var(--muted-2); }
.tag-picker-tree { border-top: 1px solid var(--line-soft); padding-top: 6px; margin-top: 2px; }
.tag-picker-node-btn {
border: 0;
background: transparent;
color: var(--link);
cursor: pointer;
padding: 3px 6px;
text-align: left;
font-size: 13px;
display: block;
width: 100%;
border-radius: var(--r);
}
.tag-picker-node-btn:hover { background: var(--paper-2); text-decoration: none; }
.tag-picker-empty { font-size: 13px; color: var(--muted-2); margin: 6px 0 0; }
/* ── Collections page (sidebar layout) ──────────────────────────────────── */
.collections-view {
padding: 24px;
}
.collections-heading {
margin: 0 0 16px;
font-size: 22px;
font-family: var(--display);
font-weight: 600;
}
.collections-error {
color: var(--accent);
font-size: 13px;
margin-bottom: 8px;
}
.coll-dismiss {
background: none;
border: none;
cursor: pointer;
color: var(--accent);
font-size: 16px;
line-height: 1;
padding: 0 4px;
}
.collections-layout {
display: grid;
grid-template-columns: 220px 1fr;
gap: 0;
border: 1px solid var(--line);
border-radius: var(--r2);
min-height: 340px;
}
.collections-sidebar {
border-right: 1px solid var(--line);
overflow-y: auto;
}
/* Sidebar list rows — renamed from .coll-row to avoid conflict with rail card */
.coll-sidebar-row {
display: flex;
flex-direction: column;
width: 100%;
padding: 10px 14px;
border: none;
border-bottom: 1px solid var(--line-soft);
background: none;
cursor: pointer;
text-align: left;
gap: 2px;
}
.coll-sidebar-row:hover { background: var(--paper-2); }
.coll-sidebar-row.is-active {
background: var(--paper-2);
border-left: 3px solid var(--accent);
}
.coll-row-name {
font-size: 14px;
font-weight: 600;
color: var(--ink);
}
.coll-row-meta {
font-size: 11px;
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.04em;
}
.coll-detail {
padding: 20px 24px;
display: flex;
flex-direction: column;
gap: 16px;
}
.coll-detail--empty {
justify-content: center;
align-items: center;
}
.coll-detail-header {
display: flex;
align-items: center;
gap: 12px;
}
.coll-detail-name {
margin: 0;
font-size: 18px;
font-family: var(--display);
font-weight: 600;
flex: 1;
}
.coll-detail-name--editable { cursor: pointer; }
.coll-detail-name--editable:hover { color: var(--link); }
.coll-edit-hint { font-size: 14px; opacity: 0.5; margin-left: 4px; }
.coll-rename-input {
flex: 1;
font-size: 16px;
font-family: var(--display);
border: 1px solid var(--line);
padding: 4px 8px;
background: var(--field);
color: var(--ink);
border-radius: var(--r);
}
.coll-delete-btn {
border: 1px solid var(--accent);
background: none;
color: var(--accent);
padding: 5px 12px;
font-size: 13px;
cursor: pointer;
border-radius: var(--r);
}
.coll-delete-btn:hover { background: var(--accent); color: var(--paper); }
.coll-detail-vis {
display: flex;
align-items: center;
gap: 10px;
}
.coll-vis-label {
font-size: 13px;
font-weight: 600;
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.04em;
white-space: nowrap;
}
.coll-vis-select {
border: 1px solid var(--line);
background: var(--paper-3);
color: var(--ink);
padding: 4px 8px;
font-size: 13px;
border-radius: var(--r);
}
.coll-section-heading {
font-size: 11px;
font-weight: 700;
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.06em;
margin-bottom: 8px;
}
.coll-entries-section { flex: 1; }
.coll-entries-list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 2px;
}
.coll-entry-row {
display: flex;
align-items: center;
gap: 10px;
padding: 7px 0;
border-bottom: 1px solid var(--line-soft);
}
.coll-entry-info {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 2px;
}
.coll-entry-title {
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.coll-entry-kind {
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.coll-entry-actions {
display: flex;
align-items: center;
gap: 6px;
flex-shrink: 0;
}
.coll-entry-vis-select {
border: 1px solid var(--line);
background: var(--paper-3);
color: var(--ink);
padding: 3px 6px;
font-size: 12px;
border-radius: var(--r);
}
.coll-entry-remove {
border: none;
background: none;
cursor: pointer;
color: var(--muted);
font-size: 18px;
line-height: 1;
padding: 0 4px;
}
.coll-entry-remove:hover { color: var(--accent); }
.coll-add-entry-form {
border-top: 1px solid var(--line-soft);
padding-top: 12px;
}
.coll-add-entry-row {
display: flex;
gap: 8px;
align-items: center;
}
.coll-add-entry-input {
flex: 1;
border: 1px solid var(--line);
background: var(--paper-3);
color: var(--ink);
padding: 6px 10px;
font-size: 13px;
min-width: 0;
border-radius: var(--r);
}
.coll-add-btn {
border: none;
background: var(--ink);
color: var(--paper);
padding: 6px 14px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
white-space: nowrap;
border-radius: var(--r);
}
.coll-add-btn:hover { opacity: 0.85; }
.coll-add-btn:disabled { opacity: 0.45; cursor: default; }
/* ── Public-session context rail summary panel ──────────────────────────── */
.rail-public-summary { padding: 4px 0; }
.rail-public-summary .rail-title { margin: 0 0 10px; }
/* old override — superseded by coll-create-details section below */
/* ── Auth loading state ─────────────────────────────────────────────────── */
.auth-loading {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
color: var(--muted);
font-size: 15px;
background: var(--paper);
}
/* ── User menu (topbar right) ───────────────────────────────────────────── */
.user-menu {
display: flex;
align-items: center;
gap: 14px;
padding-left: 6px;
flex-shrink: 0;
}
.user-name {
font-size: 12.5px;
color: var(--muted-2);
letter-spacing: 0.01em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 140px;
}
.logout-btn {
border: 1px solid rgba(255,255,255,0.18);
background: transparent;
color: #c8bfb0;
font-size: 12px;
padding: 4px 11px;
border-radius: var(--r);
cursor: pointer;
white-space: nowrap;
transition: background 0.15s, color 0.15s;
}
.logout-btn:hover { background: rgba(255,255,255,0.1); color: var(--paper); }
.logout-btn:disabled { opacity: 0.5; cursor: default; }
/* ── Login / Setup pages ─────────────────────────────────────────────────── */
.login-page,
.setup-page {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: var(--paper);
}
.login-card,
.setup-card {
width: 100%;
max-width: 360px;
padding: 40px 36px 44px;
background: var(--paper-3);
border: 1px solid var(--line);
border-radius: var(--r3);
box-shadow: 0 2px 20px rgba(20,29,24,0.07);
}
.login-brand,
.setup-brand {
font-family: var(--display);
font-size: 32px;
font-weight: 600;
color: var(--ink);
letter-spacing: -0.01em;
margin: 0 0 6px;
}
.login-tagline,
.setup-tagline {
font-size: 13px;
color: var(--muted);
margin: 0 0 28px;
}
.login-field,
.setup-field {
display: flex;
flex-direction: column;
gap: 5px;
margin-bottom: 14px;
}
.login-label,
.setup-label {
font-size: 11.5px;
font-weight: 600;
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.06em;
}
.login-input,
.setup-input {
width: 100%;
border: 1px solid var(--line);
background: var(--field);
color: var(--ink);
padding: 9px 11px;
font-size: 14px;
border-radius: var(--r2);
outline: none;
transition: border-color 0.15s;
}
.login-input:focus,
.setup-input:focus { border-color: var(--accent); }
.login-error,
.setup-error {
font-size: 13px;
color: var(--accent);
margin: 4px 0 8px;
}
.login-submit,
.setup-submit {
width: 100%;
margin-top: 8px;
border: none;
background: var(--top);
color: var(--paper);
font-size: 14px;
font-weight: 600;
padding: 11px 16px;
border-radius: var(--r2);
cursor: pointer;
letter-spacing: 0.02em;
transition: opacity 0.15s;
}
.login-submit:hover,
.setup-submit:hover { opacity: 0.85; }
.login-submit:disabled,
.setup-submit:disabled { opacity: 0.45; cursor: default; }
/* ── Shared sub-view tabs ────────────────────────────────────────────────── */
.view-tabs {
display: flex;
gap: 2px;
margin-bottom: 22px;
border-bottom: 1px solid var(--line-soft);
padding-bottom: 0;
}
.view-tab {
border: none;
background: none;
color: var(--muted);
font-size: 13px;
font-weight: 600;
padding: 7px 14px;
cursor: pointer;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
letter-spacing: 0.02em;
transition: color 0.12s;
text-transform: uppercase;
letter-spacing: 0.06em;
font-size: 11.5px;
}
.view-tab:hover { color: var(--ink); }
.view-tab.is-active { color: var(--ink); border-bottom-color: var(--accent); }
/* ── Shared form elements ────────────────────────────────────────────────── */
.form-section { margin-bottom: 32px; }
.form-section h2 {
font-size: 14px;
font-weight: 700;
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.06em;
margin: 0 0 14px;
}
.form-row { display: flex; gap: 8px; margin-bottom: 10px; }
.form-field {
display: flex;
flex-direction: column;
gap: 5px;
margin-bottom: 12px;
}
.form-label {
font-size: 11.5px;
font-weight: 600;
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.field-input {
border: 1px solid var(--line);
background: var(--field);
color: var(--ink);
padding: 8px 10px;
font-size: 13.5px;
border-radius: var(--r);
outline: none;
transition: border-color 0.15s;
min-width: 0;
}
.field-input:focus { border-color: var(--accent); }
.field-input--flex { flex: 1; }
.form-msg { font-size: 13px; margin: 6px 0; }
.form-msg--ok { color: var(--link); }
.form-msg--err { color: var(--accent); }
.btn-primary {
border: none;
background: var(--top);
color: var(--paper);
font-size: 13px;
font-weight: 600;
padding: 8px 16px;
border-radius: var(--r);
cursor: pointer;
white-space: nowrap;
}
.btn-primary:hover { opacity: 0.85; }
.btn-primary:disabled { opacity: 0.45; cursor: default; }
.btn-ghost {
border: 1px solid var(--line);
background: none;
color: var(--ink);
font-size: 13px;
padding: 7px 14px;
border-radius: var(--r);
cursor: pointer;
}
.btn-ghost:hover { background: var(--paper-2); }
.btn-danger {
border: 1px solid var(--accent);
background: none;
color: var(--accent);
font-size: 13px;
padding: 7px 14px;
border-radius: var(--r);
cursor: pointer;
}
.btn-danger:hover { background: var(--accent); color: var(--paper); }
/* ── Admin view overrides ────────────────────────────────────────────────── */
.admin-view h1 { font-family: var(--display); font-weight: 600; font-size: 26px; margin: 0 0 20px; }
.admin-table {
width: 100%;
border-collapse: collapse;
font-size: 13px;
margin-bottom: 28px;
}
.admin-table th {
text-align: left;
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.07em;
color: var(--muted);
padding: 8px 10px;
border-bottom: 1px solid var(--line);
background: var(--paper-2);
}
.admin-table th:first-child { padding-left: 16px; }
.admin-table td {
padding: 9px 10px;
border-bottom: 1px solid var(--line-soft);
color: var(--ink);
vertical-align: middle;
}
.admin-table td:first-child { padding-left: 16px; }
.admin-table tr:hover td { background: var(--paper-2); }
/* ── Settings › yt-dlp ── */
.ytdlp-section { max-width: 760px; }
.ytdlp-summary { display: grid; grid-template-columns: max-content 1fr; gap: 6px 16px; margin: 0 0 12px; font-size: 14px; }
.ytdlp-summary dt { font-weight: 700; color: var(--muted); }
.ytdlp-summary dd { margin: 0; }
.ytdlp-path { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; word-break: break-all; }
.ytdlp-table-wrap { overflow-x: auto; margin: 6px 0 14px; border: 1px solid var(--line-soft); }
.ytdlp-row--chosen td { background: var(--paper-2); }
.ytdlp-badge { font-size: 11px; font-weight: 700; color: var(--paper); background: var(--link); border-radius: 3px; padding: 1px 6px; white-space: nowrap; }
.ytdlp-actions { display: flex; gap: 8px; align-items: center; margin: 8px 0; }
.admin-row-disabled td { opacity: 0.45; }
.admin-section { margin-bottom: 36px; max-width: 860px; }
.admin-section h2 {
font-size: 14px;
font-weight: 700;
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.06em;
margin: 0 0 14px;
}
.admin-section h3 {
font-size: 13px;
font-weight: 700;
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.05em;
margin: 22px 0 10px;
}
.admin-form { display: flex; flex-direction: column; gap: 8px; max-width: 480px; }
.admin-input {
border: 1px solid var(--line);
background: var(--field);
color: var(--ink);
padding: 8px 10px;
font-size: 13.5px;
border-radius: var(--r);
outline: none;
transition: border-color 0.15s;
}
.admin-input:focus { border-color: var(--accent); }
.admin-action-btn {
border: 1px solid var(--line);
background: none;
color: var(--ink);
font-size: 12px;
padding: 4px 10px;
border-radius: var(--r);
cursor: pointer;
white-space: nowrap;
}
.admin-action-btn:hover { border-color: var(--accent); color: var(--accent); }
.status-badge {
display: inline-block;
padding: 2px 8px;
border-radius: var(--r);
font-size: 11.5px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.status-active { background: #d8eddf; color: #235c35; border: 1px solid #b4d9be; }
.status-disabled { background: #ede8e0; color: var(--muted); border: 1px solid var(--line); }
/* ── Runs view improvements ──────────────────────────────────────────────── */
.run-status {
display: inline-block;
padding: 2px 8px;
border-radius: var(--r);
font-size: 11.5px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.run-status--completed { background: #d8eddf; color: #235c35; border: 1px solid #b4d9be; }
.run-status--failed { background: #f5ddd8; color: #8d3f30; border: 1px solid #e0b8b0; }
.run-status--in-progress { background: #fdefd8; color: #8a4f10; border: 1px solid #f0cfa0; }
/* Clickable failed run rows and expandable error detail */
.run-row--failed { cursor: pointer; }
.run-row--failed:hover td { background: #fdf0ed !important; }
.run-expand-hint {
margin-left: 6px;
font-size: 10px;
color: var(--accent);
vertical-align: middle;
}
.run-error-row td {
padding: 0 !important;
background: var(--paper-2) !important;
}
.run-error-detail {
margin: 0;
padding: 10px 16px 12px;
font-family: ui-monospace, "SF Mono", Menlo, monospace;
font-size: 11.5px;
line-height: 1.55;
color: var(--muted);
white-space: pre-wrap;
word-break: break-word;
max-height: 220px;
overflow-y: auto;
}
/* ── Token created banner ────────────────────────────────────────────────── */
.token-banner {
background: #d8eddf;
border: 1px solid #b4d9be;
padding: 12px 14px;
margin-bottom: 16px;
font-size: 13px;
border-radius: var(--r2);
}
.token-banner code {
word-break: break-all;
display: block;
margin-top: 6px;
padding: 6px 8px;
background: var(--field);
border: 1px solid var(--line);
border-radius: var(--r);
font-size: 12px;
font-family: ui-monospace, "SF Mono", Menlo, monospace;
}
.token-dismiss {
margin-top: 8px;
font-size: 12px;
border: 1px solid var(--line);
background: none;
cursor: pointer;
padding: 3px 8px;
border-radius: var(--r);
color: var(--muted);
}
.token-dismiss:hover { background: var(--paper-2); }
.token-row {
display: flex;
align-items: center;
justify-content: space-between;
border: 1px solid var(--line);
background: var(--paper-3);
padding: 10px 12px;
border-radius: var(--r);
margin-bottom: 6px;
}
.token-row-info strong { font-size: 14px; display: block; }
.token-row-info .muted { font-size: 12px; margin-top: 2px; }
.token-create-row { display: flex; gap: 8px; margin-bottom: 16px; }
/* ── Instance settings checkboxes ───────────────────────────────────────── */
.checkbox-row {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 12px;
cursor: pointer;
font-size: 14px;
}
.checkbox-row input[type=checkbox] { width: 15px; height: 15px; accent-color: var(--accent); }
/* ── Collections create details ─────────────────────────────────────────── */
.coll-create-details {
margin-top: 16px;
}
.coll-create-details summary {
font-weight: 600;
cursor: pointer;
font-size: 13px;
color: var(--link);
list-style: none;
display: flex;
align-items: center;
gap: 6px;
padding: 8px 12px;
border: 1px solid var(--line-soft);
border-radius: var(--r2);
background: var(--paper-3);
width: fit-content;
}
.coll-create-details summary:hover { background: var(--paper-2); }
.coll-create-details[open] summary { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.coll-create-form {
border: 1px solid var(--line-soft);
border-top: none;
padding: 14px;
border-radius: 0 0 var(--r2) var(--r2);
background: var(--paper-3);
display: flex;
flex-direction: column;
gap: 10px;
max-width: 440px;
}
/* ── Responsive ──────────────────────────────────────────────────────────── */
@media (max-width: 900px) {
.topbar {
grid-template-columns: 1fr auto;
height: auto;
min-height: 58px;
padding: 12px;
}
.switcher,
.nav {
grid-column: 1 / -1;
}
.nav {
justify-content: flex-start;
overflow-x: auto;
}
.app-shell {
height: auto;
grid-template-columns: 1fr;
}
.context-rail {
border-left: 0;
border-top: 1px solid var(--line);
}
.entry-table { min-width: 860px; }
}
/* Inline title edit in ContextRail */
.rail-title--editable {
cursor: pointer;
}
.rail-title--editable:hover {
opacity: 0.75;
}
.rail-title--editable .edit-icon {
display: inline-block;
width: 0.75em;
height: 0.75em;
margin-left: 0.35em;
vertical-align: middle;
opacity: 0;
transition: opacity 0.1s;
flex-shrink: 0;
}
.rail-title--editable:hover .edit-icon {
opacity: 0.5;
}
.rail-title-input {
width: 100%;
font: inherit;
font-size: inherit;
font-weight: 600;
background: transparent;
border: none;
border-bottom: 1px solid currentColor;
color: inherit;
padding: 0;
margin: 0 0 8px;
outline: none;
}
/* ════════════════════════════════════════════════════════════════════
ENTRY PREVIEWS
════════════════════════════════════════════════════════════════════ */
.preview-panel {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
}
.preview-panel-loading,
.preview-panel-empty {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
gap: 8px;
color: var(--muted-2);
font-size: 14px;
text-align: center;
padding: 24px;
}
/* ── Video preview ────────────────────────────────────────────────── */
.preview-video-wrap {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
background: #0d0d0b;
min-height: 200px;
}
.preview-video-wrap video {
max-width: 100%;
max-height: 100%;
width: 100%;
display: block;
}
/* ── Cast / AirPlay TV overlay ───────────────────────────────────────── */
.video-tv-controls {
position: absolute;
top: 10px;
right: 10px;
display: flex;
gap: 6px;
z-index: 10;
}
.video-tv-btn {
display: flex;
align-items: center;
justify-content: center;
width: 34px;
height: 34px;
padding: 0;
border: none;
border-radius: 6px;
background: rgba(0, 0, 0, 0.5);
color: rgba(255, 255, 255, 0.82);
cursor: pointer;
backdrop-filter: blur(6px);
-webkit-backdrop-filter: blur(6px);
transition: background 0.15s, color 0.15s;
}
.video-tv-btn:hover {
background: rgba(0, 0, 0, 0.72);
color: #fff;
}
/* google-cast-launcher inherits color for its SVG icon */
google-cast-launcher.video-tv-btn {
color: rgba(255, 255, 255, 0.82);
}
/* Brief spinner shown while the signed media URL is being fetched */
.video-tv-loading {
width: 100%;
min-height: 200px;
background: #0d0d0b;
}
/* ── Iframe preview ───────────────────────────────────────────────── */
.preview-iframe-wrap {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
}
.preview-iframe-toolbar {
display: flex;
flex-direction: column;
gap: 2px;
padding: 6px 12px;
background: var(--paper-2);
border-bottom: 1px solid var(--line);
flex-shrink: 0;
/* never uppercase the toolbar text */
text-transform: none;
letter-spacing: normal;
}
.preview-iframe-toolbar span {
font-size: 11px;
color: var(--muted-2);
}
.preview-iframe-toolbar a {
margin-left: auto;
color: var(--link);
font-size: 12px;
text-decoration: none;
padding: 3px 8px;
border: 1px solid var(--line);
border-radius: var(--r2);
background: var(--field);
transition: border-color 0.12s;
}
.preview-iframe-toolbar a:hover {
border-color: var(--accent);
text-decoration: none;
}
.preview-iframe-wrap iframe {
flex: 1;
width: 100%;
border: none;
background: white;
min-height: 0;
}
/* ── Image preview ────────────────────────────────────────────────── */
.preview-image-wrap {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
background: var(--paper-2);
}
.preview-image-wrap img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
border-radius: var(--r3);
cursor: zoom-in;
display: block;
box-shadow: 0 4px 24px rgba(0,0,0,0.1);
}
/* ── Tweet preview wrap ───────────────────────────────────────────── */
.preview-tweet-wrap {
flex: 1;
min-height: 0;
overflow-y: auto;
padding: 12px 16px;
background: var(--paper-2);
/* styled scrollbar matching the workspace rail */
scrollbar-width: thin;
scrollbar-color: var(--line) transparent;
}
.preview-tweet-wrap::-webkit-scrollbar { width: 8px; }
.preview-tweet-wrap::-webkit-scrollbar-track { background: transparent; }
.preview-tweet-wrap::-webkit-scrollbar-thumb {
background: var(--line);
border-radius: 999px;
border: 2px solid transparent;
background-clip: padding-box;
}
.preview-tweet-wrap::-webkit-scrollbar-thumb:hover {
background: var(--muted-2);
background-clip: padding-box;
border: 2px solid transparent;
}
/* ── Tweet card ───────────────────────────────────────────────────── */
.tw-card {
border: 1px solid var(--line);
border-radius: 12px;
padding: 16px;
background: var(--paper);
max-width: 560px;
margin: 0 auto 12px;
}
.tw-thread {
max-width: 560px;
margin: 0 auto;
}
.tw-thread-item {
display: flex;
gap: 0;
margin-bottom: 0;
}
.tw-thread-connector {
display: flex;
flex-direction: column;
align-items: center;
flex-shrink: 0;
width: 52px;
padding-top: 2px;
}
.tw-thread-avatar-col {
display: flex;
flex-direction: column;
align-items: center;
flex-shrink: 0;
}
.tw-thread-line {
width: 2px;
background: var(--line);
flex: 1;
min-height: 16px;
margin: 4px 0;
}
.tw-thread-body {
flex: 1;
min-width: 0;
padding: 0 0 16px 12px;
}
.tw-thread-body:last-child { padding-bottom: 0; }
.tw-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
object-fit: cover;
flex-shrink: 0;
display: block;
}
.tw-avatar-ph {
width: 40px;
height: 40px;
border-radius: 50%;
background: var(--paper-2);
border: 1px solid var(--line);
flex-shrink: 0;
}
.tw-header {
display: flex;
align-items: baseline;
gap: 6px;
flex-wrap: wrap;
margin-bottom: 6px;
}
.tw-author-name { font-size: 14.5px; font-weight: 700; color: var(--ink); }
.tw-author-handle { font-size: 13px; color: var(--muted-2); }
.tw-dot { color: var(--muted-2); font-size: 13px; }
.tw-date { font-size: 13px; color: var(--muted-2); }
.tw-text {
font-size: 15px;
line-height: 1.65;
color: var(--ink);
white-space: pre-line;
word-break: break-word;
margin-bottom: 10px;
}
.tw-text a { color: var(--link); text-decoration: none; }
.tw-text a:hover { text-decoration: underline; }
.tw-stats {
display: flex;
gap: 20px;
color: var(--muted-2);
font-size: 13px;
margin-top: 10px;
padding-top: 10px;
border-top: 1px solid var(--line-soft);
}
.tw-stats span { display: flex; align-items: center; gap: 4px; }
/* ── X Article styles ─────────────────────────────────────────────── */
.tw-article {
max-width: 598px;
margin: 0 auto;
}
.tw-article-cover {
width: 100%;
display: block;
object-fit: cover;
max-height: 380px;
}
.tw-article-meta { padding: 20px 16px 0; }
.tw-article-title {
font-size: 22px;
font-weight: 800;
letter-spacing: -0.3px;
color: var(--ink);
line-height: 1.3;
margin-bottom: 14px;
}
.tw-article-author-row {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 14px;
}
.tw-article-author-name { font-size: 14px; font-weight: 700; color: var(--ink); }
.tw-article-author-sub { font-size: 13px; color: var(--muted-2); }
.tw-article-divider { border: none; border-top: 1px solid var(--line); margin: 0; }
.tw-article-body { padding: 8px 16px 60px; }
.tw-b-h1 {
font-size: 24px; font-weight: 800; letter-spacing: -0.3px;
color: var(--ink); line-height: 1.25; margin: 22px 0 10px;
}
.tw-b-h2 {
font-size: 19px; font-weight: 700; letter-spacing: -0.15px;
color: var(--ink); line-height: 1.3; margin: 20px 0 8px;
}
.tw-b-p { font-size: 16px; color: var(--ink); line-height: 1.72; margin-bottom: 14px; }
.tw-b-p:empty { display: none; }
.tw-b-spacer { height: 6px; display: block; }
.tw-b-blockquote {
border-left: 3px solid var(--line);
padding: 2px 14px;
margin: 14px 0;
color: var(--muted);
font-size: 16px;
line-height: 1.65;
}
.tw-b-hr { border: none; border-top: 1px solid var(--line); margin: 24px 0; }
.tw-b-img { width: 100%; display: block; border-radius: 10px; margin: 14px 0; }
.tw-b-ul, .tw-b-ol { margin: 10px 0 14px; padding-left: 26px; }
.tw-b-li { font-size: 16px; color: var(--ink); line-height: 1.65; margin-bottom: 6px; }
.tw-b-code {
font-family: ui-monospace, 'SF Mono', Menlo, monospace;
font-size: 0.875em;
background: var(--paper-2);
padding: 2px 5px;
border-radius: 4px;
color: var(--ink);
}
.tw-b-pre {
background: var(--paper-2);
border: 1px solid var(--line);
border-radius: 8px;
padding: 14px 16px;
overflow-x: auto;
margin: 12px 0;
}
.tw-b-pre code {
font-family: ui-monospace, 'SF Mono', Menlo, monospace;
font-size: 13px;
line-height: 1.6;
}
.tw-b-tweet-link {
display: flex;
align-items: center;
gap: 10px;
border: 1px solid var(--line);
border-radius: 10px;
padding: 12px 14px;
margin: 12px 0;
color: var(--muted);
font-size: 14px;
text-decoration: none;
background: var(--paper-3);
transition: background 0.12s;
}
.tw-b-tweet-link:hover { background: var(--field); }
.tw-b-tweet-link svg { flex-shrink: 0; color: var(--ink); }
/* ── Audio bar ────────────────────────────────────────────────────── */
.audio-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 72px;
background: var(--paper);
border-top: 1px solid var(--line);
display: flex;
align-items: center;
gap: 20px;
padding: 0 24px;
z-index: 100;
box-shadow: 0 -2px 16px rgba(0,0,0,0.08);
}
.audio-bar-info {
display: flex;
align-items: center;
gap: 10px;
min-width: 0;
flex: 0 0 200px;
}
.audio-bar-icon {
flex-shrink: 0;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
}
.audio-bar-icon svg { width: 20px; height: 20px; }
.audio-bar-title {
font-size: 13px;
color: var(--ink);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
font-weight: 500;
}
.audio-bar-controls {
flex: 1;
display: flex;
align-items: center;
gap: 12px;
min-width: 0;
}
.audio-bar-play-btn {
width: 38px;
height: 38px;
border-radius: 50%;
background: var(--accent);
color: var(--paper);
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: background 0.12s, transform 0.1s;
}
.audio-bar-play-btn:hover { background: var(--accent-2); }
.audio-bar-play-btn:active { transform: scale(0.93); }
.audio-bar-play-btn svg { width: 15px; height: 15px; }
.audio-bar-seek {
flex: 1;
min-width: 0;
display: flex;
align-items: center;
gap: 8px;
}
.audio-bar-seek input[type="range"] {
flex: 1;
accent-color: var(--accent);
height: 4px;
cursor: pointer;
min-width: 0;
}
.audio-bar-time {
font-size: 11.5px;
color: var(--muted-2);
white-space: nowrap;
min-width: 80px;
text-align: right;
font-variant-numeric: tabular-nums;
}
.audio-bar-right {
flex: 0 0 auto;
display: flex;
align-items: center;
gap: 10px;
}
.audio-bar-volume {
display: flex;
align-items: center;
gap: 6px;
}
.audio-bar-volume svg { width: 14px; height: 14px; color: var(--muted-2); flex-shrink: 0; }
.audio-bar-volume input[type="range"] {
width: 72px;
accent-color: var(--accent);
cursor: pointer;
}
.audio-bar-close {
width: 28px;
height: 28px;
border-radius: 50%;
border: none;
background: transparent;
color: var(--muted-2);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
padding: 0;
line-height: 1;
transition: background 0.12s, color 0.12s;
}
.audio-bar-close:hover { background: var(--field); color: var(--ink); }
/* ── Preview modal ────────────────────────────────────────────────── */
.preview-modal-backdrop {
position: fixed;
inset: 0;
z-index: 200;
background: rgba(0, 0, 0, 0.55);
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.preview-modal {
background: var(--paper);
border-radius: 12px;
box-shadow: 0 24px 80px rgba(0, 0, 0, 0.28);
width: 90vw;
max-width: 1100px;
max-height: 88vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* Full-height variant for iframe/PDF/video/image (needs explicit height
so flex children like <iframe style="flex:1"> have a concrete container). */
.preview-modal--full {
height: 88vh;
}
.preview-modal--full .preview-modal-body {
max-height: none;
}
.preview-modal-header {
display: flex;
align-items: center;
padding: 14px 18px;
border-bottom: 1px solid var(--line);
flex-shrink: 0;
gap: 12px;
}
.preview-modal-title {
flex: 1;
min-width: 0;
font-size: 14px;
font-weight: 600;
color: var(--ink);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.preview-modal-close {
width: 30px;
height: 30px;
border-radius: 50%;
border: none;
background: transparent;
color: var(--muted-2);
font-size: 20px;
line-height: 1;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: background 0.12s, color 0.12s;
}
.preview-modal-close:hover { background: var(--field); color: var(--ink); }
.preview-modal-body {
flex: 1;
min-height: 0;
/* overflow: hidden — each child (tweet-wrap, video-wrap, iframe, image)
manages its own scroll. This also prevents the spurious scrollbar that
appears when a video's native controls briefly expand the layout. */
overflow: hidden;
display: flex;
flex-direction: column;
/* Cap so long threads/articles stay scrollable even when modal has no
fixed height (shrinks for short tweets). 52px ≈ header padding+border. */
max-height: calc(88vh - 52px);
}
/* Preview button in context rail */
.rail-preview-btn {
display: block;
width: 100%;
padding: 8px 12px;
margin-bottom: 16px;
background: var(--accent);
color: var(--paper);
border: none;
border-radius: var(--r3);
font-size: 13px;
font-weight: 600;
cursor: pointer;
text-align: center;
transition: background 0.12s;
}
.rail-preview-btn:hover { background: var(--accent-2); }
/* Open-in-new-tab button in preview modal header */
.preview-modal-newtab {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border-radius: var(--r2);
color: var(--muted-2);
text-decoration: none;
font-size: 16px;
flex-shrink: 0;
transition: background 0.12s, color 0.12s;
}
.preview-modal-newtab:hover { background: var(--field); color: var(--ink); }
/* Push content above the fixed AudioBar when it is visible */
body.has-audio-bar { padding-bottom: 56px; }
/* ── In-progress entry row ──────────────────────────────────────────────── */
.in-progress-entry-row {
box-sizing: border-box;
min-width: 0;
padding: 7px 22px;
gap: 9px;
color: var(--muted);
white-space: nowrap;
}
.in-progress-entry-row__spinner {
width: 16px;
height: 16px;
border-width: 2px;
color: var(--accent);
flex-shrink: 0;
}
.in-progress-entry-row__locator {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
font-family: ui-monospace, "SF Mono", Menlo, monospace;
font-size: 11.5px;
}
.in-progress-entry-row__status {
display: inline-flex;
align-items: center;
gap: 5px;
flex-shrink: 0;
color: var(--muted-2);
font-size: 11.5px;
}
.in-progress-entry-row__kind {
font-size: 10.5px;
opacity: 0.85;
}
@media (pointer: coarse) {
.in-progress-entry-row { padding-inline: 10px; }
}
/* ── Child entry expansion ───────────────────────────────────────────────── */
/* Outer wrapper: one block per entry-group so nth-child stays correct.
#entries-body > .entry-row-outer beats #entries-body > div on specificity
(id + class > id + element) so display:flex is safely overridden. */
#entries-body > .entry-row-outer {
display: block;
border-bottom: none;
}
/* Inner flex row: replicates the #entries-body > div row behaviour. */
#entries-body > .entry-row-outer > .entry-row-main {
display: flex;
align-items: center;
cursor: default;
border-bottom: 1px solid var(--line-soft);
/* Reset padding that #entries-body > div > div would otherwise apply. */
padding: 0;
flex-shrink: unset;
overflow: visible;
}
/* Column cells inside the inner row. */
#entries-body > .entry-row-outer > .entry-row-main > div {
padding: 7px 10px;
flex-shrink: 0;
overflow: hidden;
}
#entries-body > .entry-row-outer > .entry-row-main > div:last-child { padding-right: 22px; }
#entries-body > .entry-row-outer > .entry-row-main .col-added { padding-left: 22px; }
/* Selection: class lives on outer wrapper; background + stroke scoped to inner row
so expanded child entries don't inherit the selection highlight. */
#entries-body > .entry-row-outer.is-selected { background: unset; outline: none; box-shadow: none; }
#entries-body > .entry-row-outer.is-multi-selected { background: unset; outline: none; box-shadow: none; }
#entries-body > .entry-row-outer.is-selected > .entry-row-main {
background: #eee2d2;
box-shadow: inset 0 0 0 2px var(--accent);
}
#entries-body > .entry-row-outer.is-multi-selected > .entry-row-main {
background: #eee2d2;
box-shadow: inset 0 0 0 2px var(--accent);
}
/* URL overflow on hover only — explicit pointer, not selection. */
#entries-body > .entry-row-outer .url-cell:hover { overflow: visible; white-space: normal; }
/* child-entries container: reset the padding that #entries-body > div > div applies. */
#entries-body > .entry-row-outer > .child-entries {
display: block;
padding: 0;
flex-shrink: unset;
overflow: visible;
border-left: 2px solid var(--line-soft);
margin-left: 32px;
}
/* Each child row reuses the same .col-* flex widths as normal rows. */
.child-entry-row {
display: flex;
align-items: center;
cursor: default;
border-bottom: 1px solid var(--line-soft);
opacity: 0.88;
}
.child-entry-row:hover { opacity: 1; }
.child-entry-row:last-child { border-bottom: none; }
.child-entry-row--light { background: #fafaf8; }
.child-entry-row--dark { background: #f2f0ec; }
.child-entry-row.is-selected {
background: #eee2d2;
box-shadow: inset 0 0 0 2px var(--accent);
opacity: 1;
}
.child-entry-row.is-multi-selected {
background: #eee2d2;
box-shadow: inset 0 0 0 2px var(--accent);
opacity: 1;
}
.child-entry-row > div {
padding: 6px 10px;
flex-shrink: 0;
overflow: hidden;
}
.child-entry-row .col-added { padding-left: 22px; }
.child-entry-row > div:last-child { padding-right: 22px; }
/* Child reorder: drag handle or move buttons inside .col-title, never both.
The arrows are the default (touch, no pointer, phone-sized ≤640px viewports,
and any browser that can't evaluate the query below). The one media query
switches a mouse/trackpad on a wider viewport to the drag handle, so the two
cases are exact complements without range syntax. Alt+↑/↓ on a focused row
works everywhere. */
.child-reorder-controls {
display: inline-flex;
align-items: center;
gap: 4px;
flex-shrink: 0;
transition: opacity 0.15s;
}
.child-drag-handle {
display: none;
cursor: grab;
padding: 0 3px;
font-size: 0.8em;
letter-spacing: -2px;
user-select: none;
color: var(--muted);
}
.child-drag-handle:active { cursor: grabbing; }
.child-move-btn {
width: 28px;
height: 28px;
padding: 0;
border: none;
background: none;
color: inherit;
font-size: 0.9em;
line-height: 1;
cursor: pointer;
}
.child-move-btn:disabled { opacity: 0.3; cursor: default; }
.child-move-btn:focus { outline: none; }
.child-move-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-radius: 2px; }
@media (hover: hover) and (pointer: fine) and (min-width: 641px) {
/* Dimmed until the row is hovered/focused; there is hover to reveal it. */
.child-reorder-controls { gap: 1px; opacity: 0.3; }
.child-entry-row:hover .child-reorder-controls,
.child-entry-row:focus-within .child-reorder-controls { opacity: 1; }
.child-drag-handle { display: inline; }
.child-move-btn { display: none; }
}
.child-entry-row.is-dragging { opacity: 0.4; }
.child-entry-row.is-drop-before { box-shadow: inset 0 2px 0 var(--accent); }
.child-entry-row.is-drop-after { box-shadow: inset 0 -2px 0 var(--accent); }
.child-entries[aria-busy="true"] .child-entry-row { cursor: progress; }
/* Expand chevron button */
.entry-expand-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
flex-shrink: 0;
padding: 0;
margin-right: 2px;
background: none;
border: none;
cursor: pointer;
opacity: 0.45;
color: inherit;
transition: opacity 0.15s;
}
.entry-expand-btn:focus { outline: none; }
.entry-expand-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }
.entry-expand-btn::before {
content: '';
display: block;
width: 0;
height: 0;
border-top: 4px solid transparent;
border-bottom: 4px solid transparent;
border-left: 6px solid currentColor;
transition: transform 0.15s;
}
.entry-expand-btn:hover { opacity: 1; }
.entry-expand-btn.is-expanded::before { transform: rotate(90deg); }
/* Child count badge next to title */
.child-count-badge {
display: inline-block;
margin-left: 5px;
padding: 0 5px;
font-size: 0.72em;
font-weight: 600;
background: color-mix(in srgb, var(--line-soft) 60%, transparent);
border-radius: 10px;
opacity: 0.75;
vertical-align: middle;
line-height: 1.6;
}
/* Loading placeholder inside child-entries */
.child-entries-loading {
padding: 8px 12px;
font-size: 0.85em;
opacity: 0.55;
}
/* ── Playlist quality expansion ──────────────────────────── */
.capture-playlist-toggle {
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 0.75rem;
color: var(--muted);
background: none;
border: none;
cursor: pointer;
padding: 2px 6px;
}
.capture-playlist-toggle:hover { color: var(--text); }
.capture-playlist-toggle--left {
flex-shrink: 0;
padding: 2px 4px;
font-size: 0.7rem;
}
.capture-conflict-badge {
font-size: 0.7rem;
color: #c07000;
background: #fff3cd;
border: 1px solid #e0a000;
border-radius: 4px;
padding: 1px 6px;
margin-left: 6px;
}
.capture-playlist-items {
border-top: 1px solid var(--line-soft);
max-height: 320px;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: var(--line) transparent;
}
.capture-playlist-item {
display: flex;
align-items: center;
gap: 8px;
padding: 5px 10px 5px 14px;
font-size: 0.8rem;
border-bottom: 1px solid var(--line-soft);
border-left: 3px solid transparent;
}
.capture-playlist-item:last-of-type { border-bottom: none; }
.capture-playlist-item--conflict {
border-left-color: #c07000;
background: color-mix(in srgb, #c07000 6%, transparent);
}
.capture-playlist-item-title {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--text);
opacity: 0.9;
}
.capture-item-quality {
font-size: 0.73rem;
padding: 2px 4px;
border: 1px solid var(--line);
border-radius: 3px;
background: var(--paper-3);
color: var(--text);
flex-shrink: 0;
}
.capture-playlist-conflict-badge {
font-size: 0.68rem;
font-weight: 600;
color: #c07000;
white-space: nowrap;
flex-shrink: 0;
}
.capture-playlist-item-remove {
flex-shrink: 0;
display: inline-flex;
align-items: center;
justify-content: center;
width: 18px;
height: 18px;
padding: 0;
border: none;
background: none;
color: var(--muted);
cursor: pointer;
border-radius: 3px;
opacity: 0.3;
transition: opacity 0.1s, color 0.1s;
}
.capture-playlist-item:hover .capture-playlist-item-remove,
.capture-playlist-item-remove:focus-visible { opacity: 1; }
.capture-playlist-item-remove:hover { color: #c04000; opacity: 1; }
@media (pointer: coarse) { .capture-playlist-item-remove { opacity: 1; } }
.capture-playlist-item-remove { font-size: 0.75rem; line-height: 1; }
.capture-sync-row {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
font-size: 0.78rem;
color: var(--muted);
border-top: 1px solid var(--line-soft);
cursor: pointer;
}
.capture-sync-row input[type=checkbox] { cursor: pointer; }
/* ── Summary rail section ────────────────────────────────────────────────── */
/* Reuses .rail-section spacing and .rail-rearchive-btn for the action button;
only the summary-specific typography and the provider row are new here. */
.rail-summary-body { margin-bottom: 10px; }
.rail-summary-tldr {
margin: 0 0 8px;
font-size: 13.5px;
font-weight: 600;
color: var(--ink);
line-height: 1.45;
}
.rail-summary-text {
margin: 0 0 8px;
font-size: 13px;
color: var(--ink);
line-height: 1.55;
}
.rail-summary-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 8px; }
.rail-summary-tag {
font-size: 11px;
padding: 2px 7px;
border: 1px solid var(--line);
border-radius: 999px;
color: var(--muted);
}
.rail-summary-provider {
margin: 0;
font-size: 11px;
color: var(--muted-2);
letter-spacing: 0.02em;
}
.rail-summary-status {
display: flex; align-items: center; gap: 7px;
margin: 0 0 8px;
font-size: 12.5px;
color: var(--muted);
}
.rail-summary-info {
margin: 0 0 8px;
padding: 8px;
color: var(--muted);
background: var(--paper-2);
border: 1px solid var(--line-soft);
border-radius: 4px;
}
.rail-summary-info__heading {
margin: 0 0 4px;
color: var(--ink);
font-size: 12.5px;
font-weight: 600;
}
.rail-summary-info__detail {
margin: 0;
font-size: 12px;
line-height: 1.45;
}
.rail-summary-error { margin: 0 0 8px; }
.rail-summary-spinner {
width: 11px; height: 11px;
border: 1.5px solid var(--line);
border-top-color: var(--muted);
border-radius: 50%;
animation: rail-summary-spin 0.7s linear infinite;
flex-shrink: 0;
}
@keyframes rail-summary-spin { to { transform: rotate(360deg); } }
/* Respect a reduced-motion preference: the text alone still conveys the state. */
@media (prefers-reduced-motion: reduce) {
.rail-summary-spinner { animation: none; }
}
.rail-summary-controls { display: flex; flex-direction: column; gap: 6px; }
.rail-summary-select {
width: 100%;
padding: 5px 8px;
font-size: 12.5px;
color: var(--ink);
background: var(--paper);
border: 1px solid var(--line);
border-radius: 4px;
}
.rail-summary-image-option {
padding: 7px 8px;
color: var(--muted);
background: var(--paper);
border: 1px solid var(--line);
border-radius: 4px;
}
.rail-summary-image-option__label {
display: flex;
align-items: center;
gap: 6px;
color: var(--ink);
font-size: 12.5px;
cursor: pointer;
}
.rail-summary-image-option__label input[type="checkbox"] {
margin: 0;
accent-color: var(--accent);
cursor: pointer;
}
.rail-summary-image-option__label input[type="checkbox"]:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.rail-summary-image-option__note {
margin: 5px 0 0;
font-size: 11px;
line-height: 1.4;
}
.rail-summary-transcribe-note {
margin: 0;
font-size: 11px;
line-height: 1.4;
color: var(--muted);
}
.rail-summary-image-option--disabled {
color: var(--muted-2);
background: var(--paper);
}
.rail-summary-image-option--disabled .rail-summary-image-option__label {
color: var(--muted-2);
cursor: not-allowed;
}
.rail-summary-image-option--disabled .rail-summary-image-option__label input[type="checkbox"] {
cursor: not-allowed;
}
/* ── Text / Markdown preview ────────────────────────────────────────────── */
.text-preview {
padding: 32px 40px 48px;
max-width: 780px;
margin: 0 auto;
font-family: var(--sans);
color: var(--ink);
overflow: auto;
height: 100%;
box-sizing: border-box;
}
.text-preview--loading,
.text-preview--error {
padding: 24px;
color: var(--muted);
font-size: 13px;
}
.text-preview--error { color: var(--accent); }
.text-preview__title {
font-family: var(--serif, var(--sans));
font-size: 22px;
font-weight: 600;
margin: 0 0 20px;
line-height: 1.25;
color: var(--ink);
}
.text-preview__body {
white-space: pre-wrap;
overflow-wrap: anywhere;
word-break: break-word;
font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
font-size: 13.5px;
line-height: 1.65;
color: var(--ink);
background: var(--paper);
border: 1px solid var(--line);
border-radius: var(--r2);
padding: 16px 18px;
margin: 0;
}
.text-preview__mime {
margin-top: 12px;
font-size: 11px;
color: var(--muted);
letter-spacing: .04em;
text-align: right;
}