:root {
    color-scheme: dark;
    --bg: #09090b;
    --surface: rgba(24, 24, 27, .55);
    --surface-2: #131318;
    --surface-3: #1a1a20;
    /* Settings surfaces sit above the page: a touch lighter than the
       background, with a soft shadow so a settings card reads as its own
       block instead of blending into the page. */
    --surface-raised: #17171c;
    --shadow-raised: inset 0 1px 0 rgba(255, 255, 255, .03), 0 12px 28px rgba(0, 0, 0, .35);
    --border: rgba(39, 39, 42, .6);
    --border-strong: #3f3f46;
    --text: #fafafa;
    --muted: #a1a1aa;
    --muted-2: #8b8b96;
    --accent: #2dd4bf;
    --accent-strong: #14b8a6;
    --accent-soft: rgba(45, 212, 191, .10);
    --accent-hover: #0d9488;
    /* Text on an accent-filled surface, and readable accent text on the
       page background. Dark theme accents are bright, so filled buttons
       take near-black text (white on #14b8a6 is only 2.5:1). */
    --accent-contrast: #09090b;
    --accent-text: var(--accent);
    --success: #34d399;
    --success-soft: rgba(52, 211, 153, .10);
    --warning: #fbbf24;
    --warning-soft: rgba(251, 191, 36, .10);
    --danger: #fb7185;
    --danger-soft: rgba(251, 113, 133, .10);
    --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    --shadow: 0 1px 2px rgba(0, 0, 0, .5), 0 12px 28px rgba(0, 0, 0, .25);
    --radius: 10px;
    --sidebar-width: 248px;
}

:root[data-theme="light"] {
    color-scheme: light;
    --bg: #fafafa;
    --surface: #ffffff;
    --surface-2: #f4f4f5;
    --surface-3: #ebebeb;
    --surface-raised: #ffffff;
    --shadow-raised: 0 1px 3px rgba(16, 24, 40, .08), 0 12px 28px rgba(16, 24, 40, .10);
    --border: #e4e4e7;
    --border-strong: #d4d4d8;
    --text: #18181b;
    --muted: #52525b;
    --muted-2: #71717a;
    --accent: #0f766e;
    --accent-strong: #0f766e;
    --accent-soft: rgba(15, 118, 110, .10);
    --accent-hover: #115e59;
    /* Light accents are dark enough for white text; accent text leans on
       the strong shade where the palette defines a lighter accent. */
    --accent-contrast: #ffffff;
    --accent-text: var(--accent-strong);
    --success: #059669;
    --success-soft: rgba(5, 150, 105, .10);
    --warning: #b45309;
    --warning-soft: rgba(180, 83, 9, .10);
    --danger: #e11d48;
    --danger-soft: rgba(225, 29, 72, .10);
    --shadow: 0 1px 2px rgba(0, 0, 0, .06), 0 10px 24px rgba(15, 23, 42, .08);
}

/* Accent palettes: the base teal ships on :root; data-accent on the
   html element swaps the four accent tokens, hover included, so no
   accent-colored rule anywhere carries a literal color. Dark variants
   first, then each palette's light-mode pair (same pattern as
   data-theme). */
:root[data-accent="teal"] {
    --accent: #2dd4bf;
    --accent-strong: #14b8a6;
    --accent-soft: rgba(45, 212, 191, .10);
    --accent-hover: #0d9488;
}
:root[data-accent="teal"][data-theme="light"] {
    --accent: #0f766e;
    --accent-strong: #0f766e;
    --accent-soft: rgba(15, 118, 110, .10);
    --accent-hover: #115e59;
}
:root[data-accent="blue"] {
    --accent: #60a5fa;
    --accent-strong: #3b82f6;
    --accent-soft: rgba(59, 130, 246, .10);
    --accent-hover: #2563eb;
}
:root[data-accent="blue"][data-theme="light"] {
    --accent: #2563eb;
    --accent-strong: #1d4ed8;
    --accent-soft: rgba(37, 99, 235, .10);
    --accent-hover: #1e40af;
}
:root[data-accent="violet"] {
    --accent: #c084fc;
    --accent-strong: #a855f7;
    --accent-soft: rgba(168, 85, 247, .10);
    --accent-hover: #9333ea;
}
:root[data-accent="violet"][data-theme="light"] {
    --accent: #7c3aed;
    --accent-strong: #6d28d9;
    --accent-soft: rgba(109, 40, 217, .10);
    --accent-hover: #5b21b6;
}
:root[data-accent="rose"] {
    --accent: #fb7185;
    --accent-strong: #f43f5e;
    --accent-soft: rgba(244, 63, 94, .10);
    --accent-hover: #e11d48;
}
:root[data-accent="rose"][data-theme="light"] {
    --accent: #e11d48;
    --accent-strong: #be123c;
    --accent-soft: rgba(190, 18, 60, .10);
    --accent-hover: #9f1239;
}
:root[data-accent="amber"] {
    --accent: #fbbf24;
    --accent-strong: #f59e0b;
    --accent-soft: rgba(245, 158, 11, .10);
    --accent-hover: #d97706;
}
:root[data-accent="amber"][data-theme="light"] {
    --accent: #b45309;
    --accent-strong: #92400e;
    --accent-soft: rgba(146, 64, 14, .10);
    --accent-hover: #78350f;
}

:root[data-accent="cyan"] {
    --accent: #22d3ee;
    --accent-strong: #06b6d4;
    --accent-soft: rgba(6, 182, 212, .10);
    --accent-hover: #0891b2;
}
:root[data-accent="cyan"][data-theme="light"] {
    --accent: #0e7490;
    --accent-strong: #155e75;
    --accent-soft: rgba(14, 116, 144, .10);
    --accent-hover: #164e63;
}
:root[data-accent="green"] {
    --accent: #4ade80;
    --accent-strong: #22c55e;
    --accent-soft: rgba(34, 197, 94, .10);
    --accent-hover: #16a34a;
}
:root[data-accent="green"][data-theme="light"] {
    --accent: #15803d;
    --accent-strong: #166534;
    --accent-soft: rgba(21, 128, 61, .10);
    --accent-hover: #14532d;
}
:root[data-accent="orange"] {
    --accent: #fb923c;
    --accent-strong: #f97316;
    --accent-soft: rgba(249, 115, 22, .10);
    --accent-hover: #ea580c;
}
:root[data-accent="orange"][data-theme="light"] {
    --accent: #c2410c;
    --accent-strong: #9a3412;
    --accent-soft: rgba(194, 65, 12, .10);
    --accent-hover: #7c2d12;
}
:root[data-accent="slate"] {
    --accent: #cbd5e1;
    --accent-strong: #94a3b8;
    --accent-soft: rgba(148, 163, 184, .12);
    --accent-hover: #64748b;
}
:root[data-accent="slate"][data-theme="light"] {
    --accent: #475569;
    --accent-strong: #334155;
    --accent-soft: rgba(71, 85, 105, .10);
    --accent-hover: #1e293b;
}

html, body {
    margin: 0;
    min-height: 100%;
    font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    background: var(--bg);
    color: var(--text);
}

* { box-sizing: border-box; }
a { color: inherit; }
button, input, select { font: inherit; }
h1, h2, h3, p { margin-top: 0; }
h1 { font-size: 1.625rem; line-height: 1.2; letter-spacing: -.01em; font-weight: 650; margin-bottom: .5rem; }
h2 { font-size: 1rem; line-height: 1.3; font-weight: 650; margin-bottom: .35rem; }
h3 { font-size: .9rem; font-weight: 600; }
p { color: var(--muted); line-height: 1.55; }
small { color: var(--muted-2); }
code { color: var(--text); background: var(--accent-soft); border-radius: 6px; padding: .08rem .35rem; }
/* Navigation focuses the page heading for screen readers; the UA ring
   around a non-interactive title reads as a glitch, so it stays off. */
h1:focus { outline: none; }

.app-shell {
    min-height: 100vh;
    display: grid;
    grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
    /* Rows size to their content: on a short page the mobile nav strip
       must not stretch to half the screen with an empty band. */
    align-content: start;
    background: var(--bg);
}

.app-sidebar {
    position: sticky;
    top: 0;
    height: 100vh;
    min-width: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding: 1rem;
    background: var(--surface);
    border-right: 1px solid var(--border);
}

.app-main { min-width: 0; }

/* The topbar used to repeat the page h1; that duplication is gone, so
   only the action-row helper remains (pages put their buttons in it). */
.topbar-actions { display: flex; align-items: center; gap: .65rem; flex-shrink: 0; flex-wrap: wrap; justify-content: flex-end; }
.app-content { width: min(1180px, calc(100vw - var(--sidebar-width) - 3rem)); padding: 1.5rem; }

.brand-block {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .35rem .25rem 1rem;
    margin-bottom: .75rem;
    border-bottom: 1px solid var(--border);
    text-decoration: none;
}

.brand-logo {
    width: 36px;
    height: 36px;
    border-radius: 9px;
    display: block;
}

/* The mark is inline SVG now: the tile takes the accent, the note the
   readable contrast color, so a theme or accent swap repaints it. */
.brand-logo-bg { fill: var(--accent); }
.brand-logo-ink { fill: var(--accent-contrast); }
.brand-logo-line {
    fill: none;
    stroke: var(--accent-contrast);
    stroke-width: 2.2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.brand-block strong { display: block; font-size: .95rem; }
.brand-block span { display: block; color: var(--muted); font-size: .8rem; }
.brand-block:hover .brand-text strong { color: var(--accent-text); }
.navbar-toggler { display: none; }

.app-nav {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    min-height: 0;
    overflow-y: auto;
    gap: .25rem;
}

.nav-section {
    margin-bottom: .65rem;
}

.nav-section-header {
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--muted);
    letter-spacing: 0;
    padding: 0 0.75rem;
    margin-bottom: 0.3rem;
}

.app-nav .nav-link {
    min-height: 36px;
    display: flex;
    gap: .65rem;
    align-items: center;
    padding: .45rem .65rem;
    border-radius: 8px;
    color: var(--muted);
    text-decoration: none;
    font-size: .9rem;
    font-weight: 500;
}

.app-nav .nav-link span {
    width: 20px;
    display: inline-grid;
    place-items: center;
    color: var(--muted-2);
}

.app-nav .nav-link:hover { background: var(--surface-2); color: var(--text); }
.app-nav .nav-link.active { background: var(--accent-soft); color: var(--accent-text); }
.app-nav .nav-link.active span { color: var(--accent-text); }

/* A login problem on any plugin follows the user everywhere: a small
   red flag on the Plugins link, so the fix is one click away. */
.app-nav .nav-link .nav-auth-flag {
    width: 18px;
    height: 18px;
    margin-left: auto;
    display: inline-grid;
    place-items: center;
    flex-shrink: 0;
    border-radius: 50%;
    background: var(--danger);
    color: var(--bg);
    font-size: 11px;
    font-weight: 800;
    line-height: 1;
}

.sidebar-footer {
    position: static;
    margin-top: auto;
    display: flex;
    gap: .65rem;
    align-items: center;
    justify-content: space-between;
    padding: .6rem .75rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-2);
}
.sidebar-footer small { display: block; color: var(--muted-2); }
.sidebar-tools { display: flex; align-items: center; gap: .15rem; }
.notification-bell { position: relative; }
.bell-count {
    position: absolute;
    top: -.25rem;
    right: -.2rem;
    min-width: 16px;
    height: 16px;
    padding: 0 .22rem;
    display: inline-grid;
    place-items: center;
    border: 2px solid var(--surface-2);
    border-radius: 99px;
    background: var(--danger);
    color: var(--bg);
    font-size: .62rem;
    font-weight: 800;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}
.theme-toggle {
    border: 0;
    background: none;
    cursor: pointer;
    font-size: 1.05rem;
    color: var(--muted);
    padding: .2rem .4rem;
    border-radius: 6px;
    line-height: 1;
}
.theme-toggle:hover { background: var(--bg); color: var(--text); }

.eyebrow {
    display: block;
    color: var(--muted-2);
    letter-spacing: .02em;
    font-size: 11.5px;
    font-weight: 600;
    margin-bottom: .35rem;
}

.hero-panel,
.panel-card,
.stat-card,
.hero-card,
.account-card,
.profile-row {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    transition: border-color .15s ease;
}

/* Hover feedback only where a click does something: stat tiles and the
   playlist card shell are not links (the cover and title are). */
.panel-card:hover:not(.playlist-card),
.account-card:hover,
.profile-row:hover { border-color: var(--border-strong); }
.playlist-cover:hover { box-shadow: 0 0 0 2px var(--accent-soft); }

.hero-panel {
    min-height: 260px;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 280px;
    gap: 1.25rem;
    align-items: end;
    padding: 1.5rem;
}
.hero-panel p { max-width: 680px; font-size: 1rem; }
.hero-card { padding: 1rem; background: var(--surface-2); box-shadow: none; }
.hero-card strong { display: block; margin-top: .6rem; }
.hero-actions { display: flex; flex-wrap: wrap; gap: .65rem; margin-top: 1rem; }

.page-title {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    align-items: end;
    margin-bottom: 1rem;
}
.page-title p { max-width: 720px; margin-bottom: 0; }

.stat-grid,
.content-grid { display: grid; gap: 1rem; margin-top: 1rem; }
.stat-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.stat-grid.two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.content-grid.two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.content-grid.three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* Dashboard right column: two stacked panels instead of one card that
   ends halfway, so both columns close around the same height.
   minmax(0, 1fr) lets the column shrink: a plain 1fr would inherit the
   inner table's 640px floor and widen the whole page. */
.grid-stack { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1rem; align-content: start; min-width: 0; }
.updated-note { font-variant-numeric: tabular-nums; }

.panel-card,
.stat-card { padding: 1rem; }
.stat-card { min-height: 0; }
.panel-header { display: flex; justify-content: space-between; gap: 1rem; align-items: start; margin-bottom: 1rem; }
/* A card that holds one short message (the error page, the OAuth
   callback): the same surface, capped to a readable measure and
   optionally centered. */
.narrow-card { max-width: 480px; }
.narrow-card.centered { margin-inline: auto; }

/* A titled block inside a card: the rhythm every settings and panel card
   shares, so a section never depends on which surface holds it. The
   divider gives a following section its own start instead of running
   into the previous one. */
.settings-section { display: grid; gap: .75rem; align-content: start; }
.settings-section + .settings-section {
    padding-top: 1rem;
    border-top: 1px solid var(--border);
}
.settings-section > .eyebrow { margin-bottom: 0; }
/* A button is a grid child inside a section: keep its natural width
   instead of stretching it across the card. */
.settings-section > .btn-modern { justify-self: start; }
/* Section heading inside a card: eyebrow, a title and an optional help
   tip, with the section grid owning the spacing. */
.settings-section > .section-head { display: grid; gap: .15rem; }
.settings-section > .section-head h3 { margin: 0; font-size: 1rem; }
/* Inside a section the grid owns the spacing: drop the pull-up margin. */
.settings-section .panel-description { margin: 0; }
.stat-icon,
.provider-icon {
    display: inline-grid;
    place-items: center;
    border-radius: 8px;
    background: var(--surface-2);
    color: var(--accent-strong);
}
.stat-icon { width: 36px; height: 36px; margin-bottom: .75rem; }
.provider-icon { width: 42px; height: 42px; font-size: 1.05rem; }
.about-card p { color: var(--muted); margin-bottom: 1rem; }
.github-link { width: fit-content; gap: .5rem; }
.stat-card label { display: block; color: var(--muted); font-size: .8rem; line-height: 1.3; }
.stat-card strong { display: block; margin: .25rem 0 .15rem; line-height: 1.2; font-size: 1.625rem; font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
.stat-card small { display: block; color: var(--muted-2); font-size: .78rem; line-height: 1.4; margin-top: .1rem; }

.btn-modern,
.icon-button {
    min-height: 38px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    color: var(--text);
    font-weight: 700;
    text-decoration: none;
    cursor: pointer;
}
.btn-modern { gap: .45rem; padding: .55rem .85rem; }
.btn-modern.small { padding: .32rem .6rem; font-size: .82rem; min-height: 0; }
.icon-button { width: 38px; padding: 0; font-size: 1rem; }
.btn-modern.primary { background: var(--accent-strong); border-color: transparent; color: var(--accent-contrast); }
.btn-modern.primary:hover { background: var(--accent-hover); }
.btn-modern.danger { background: transparent; border-color: rgba(251, 113, 133, .25); color: var(--danger); }
.btn-modern.danger:hover { background: rgba(159, 18, 57, .45); color: var(--danger); }
.btn-modern.primary-outline { background: transparent; border-color: var(--accent); color: var(--accent-text); }
.btn-modern.secondary,
.btn-modern.subtle { background: var(--surface-2); border-color: var(--border); color: var(--text); }
.btn-modern.secondary:hover,
.btn-modern.subtle:hover { background: var(--surface-3); border-color: var(--border-strong); }
.btn-modern.ghost { background: transparent; border-color: var(--border); color: var(--muted); }
.btn-modern.ghost:hover { background: var(--surface-2); border-color: var(--border-strong); color: var(--text); }
.btn-modern:hover,
.icon-button:hover { border-color: var(--border-strong); }
.btn-modern:disabled { opacity: .55; cursor: wait; }
/* Keyboard users get a ring; mouse users keep the plain hover. */
.btn-modern:focus-visible,
.icon-button:focus-visible,
.theme-toggle:focus-visible,
.filter-chip:focus-visible,
.tab-link:focus-visible,
.nav-link:focus-visible,
a:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.pill {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    min-height: 22px;
    padding: .2rem .6rem;
    border-radius: 999px;
    font-size: .72rem;
    font-weight: 600;
    border: 1px solid transparent;
    white-space: nowrap;
    background: var(--surface-2);
    color: var(--muted);
}
.pill .dot {
    width: 6px;
    height: 6px;
    border-radius: 999px;
    background: currentColor;
    animation: pill-dot-pulse 1.4s ease-in-out infinite;
}
/* A pill with an action behind it: the button chrome disappears, the
   pill keeps its colors, and hover/focus make it read as clickable. */
.pill-button {
    display: inline-flex;
    align-items: center;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: inherit;
    font: inherit;
    cursor: pointer;
}
.pill-button .pill { transition: border-color .15s ease, filter .15s ease; }
.pill-button:hover .pill { border-color: var(--border-strong); filter: brightness(1.08); }
.pill-button:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
@keyframes pill-dot-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: .35; transform: scale(.8); }
}
.account-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 1rem; }
/* Four provider cards in the import modal read better as a 2x2 block than
   a three-up row with one card stranded below it. */
.import-account-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 760px) { .import-account-grid { grid-template-columns: 1fr; } }
.account-card { display: flex; flex-direction: column; gap: .6rem; padding: 1rem; border: 1px solid var(--border); border-radius: var(--radius); }
.account-card .pill { align-self: flex-start; }
.account-card label { margin: 0; }

.qi-warn { color: var(--warning); font-weight: 600; margin-left: .5rem; }

.pill.ok { color: var(--success); background: var(--success-soft); border-color: rgba(52, 211, 153, .2); }
.pill.warn, .pill.warning { color: var(--warning); background: var(--warning-soft); border-color: rgba(251, 191, 36, .2); }
.pill.err { color: var(--danger); background: var(--danger-soft); border-color: rgba(251, 113, 133, .2); }
.pill.neutral { color: var(--muted); background: var(--surface-2); border-color: var(--border); }
.pill.info { color: var(--accent-strong); background: var(--accent-soft); border-color: color-mix(in srgb, var(--accent) 20%, transparent); }
:root[data-theme="light"] .pill.neutral { background: #f4f4f5; color: #52525b; border-color: #e4e4e7; }
/* Light theme pill text: the dark-theme success/warning/danger shades sit
   just under AA on white, so the light theme uses deeper ones. */
:root[data-theme="light"] .pill.ok { color: #065f46; border-color: rgba(6, 95, 70, .25); }
:root[data-theme="light"] .pill.warn,
:root[data-theme="light"] .pill.warning { color: #92400e; border-color: rgba(146, 64, 14, .25); }
:root[data-theme="light"] .pill.err { color: #be123c; border-color: rgba(190, 18, 60, .25); }

.status-dot { width: 9px; height: 9px; border-radius: 999px; display: inline-block; }
.status-dot.online { background: var(--success); }
.status-dot.warning { background: var(--warning); }

input,
select {
    width: 100%;
    min-height: 40px;
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: .55rem .7rem;
    background: var(--bg);
    color: var(--text);
    outline: none;
}
input:focus,
select:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

/* ── Fields ───────────────────────────────────────────────────────── */
/* One field is a label, its control and an optional note. The label can
   wrap the control (label > input, the compact form) or stand alone
   (label[for] + input); both keep the same rhythm, so settings markup
   may pick whichever fits and still look identical. */
.field,
.form-grid label { display: grid; gap: .4rem; align-content: start; }
.field > label,
.field-label,
.form-grid label { color: var(--muted); font-size: .82rem; font-weight: 700; }
/* Notes under a field: muted, never bold (labels are bold, their
   explanation is not). */
.field-hint,
.form-grid label small { color: var(--muted); font-size: .8rem; font-weight: 400; line-height: 1.45; }

/* The two-column field layout; .single stacks, .wide spans. */
.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; align-items: start; }
.form-grid.single { grid-template-columns: 1fr; }
.form-grid .wide { grid-column: 1 / -1; }

/* ── Settings surfaces ────────────────────────────────────────────── */
/* One surface for every block that holds settings: the Settings tabs, the
   plugin panel, the playlist settings, the Advanced page and the job
   forms. The card is raised (--surface-raised plus --shadow-raised) so it
   reads as separate from the page instead of blending into it, and the
   head, the sections and the actions keep the same rhythm everywhere.
   Page styles only add their own layout on top of this, never a second
   surface. The blocks inside a card come from the shared vocabulary:
   fields use .field or the .form-grid label pattern, notes use
   .hint-box, toggle rows use .toggle-row or .toggle-switch.wide, and
   action rows use .flex-actions. */
.settings-card {
    display: grid;
    gap: 1rem;
    padding: 1.15rem 1.25rem 1.25rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-raised);
    box-shadow: var(--shadow-raised);
}
/* Head: eyebrow, title and an optional right-side state or action. Same
   block as a panel head, minus the bottom margin: inside a settings card
   the card grid owns the rhythm. */
.settings-head {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    align-items: start;
}
.settings-head > div { display: grid; gap: .2rem; }
.settings-head h2,
.settings-head h3 { margin: 0; font-size: 1.05rem; letter-spacing: -.01em; }
.settings-head .panel-description,
.settings-head > p { margin: 0; }
/* Sections inside the card keep the shared .settings-section rhythm
   defined next to the card rules above. */

.timeline-list,
.health-list,
.provider-list { display: grid; gap: .65rem; }
.timeline-item,
.health-list > div,
.provider-row {
    display: flex;
    gap: .75rem;
    align-items: center;
    padding: .75rem;
    border-radius: 8px;
    background: var(--surface-3);
}
.timeline-item span:first-child {
    width: 26px;
    height: 26px;
    display: grid;
    place-items: center;
    border-radius: 999px;
    background: var(--bg);
    color: var(--muted);
    font-size: .82rem;
    font-weight: 800;
}
.timeline-item.done span:first-child,
.timeline-item.active span:first-child { background: var(--accent-soft); color: var(--accent-strong); }
.timeline-item p,
.health-list small,
.provider-row small { margin: 0; }
.health-list > div { justify-content: start; }
.account-card { display: grid; gap: .85rem; }
/* Account card header: provider name, state pill and the optional
   disconnect action on one line. */
.account-head { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.account-head strong { font-size: 1rem; }
.account-head .btn-modern { margin-left: auto; }
/* Two state pills (unofficial + connection) wrap as one unit, so a narrow
   card never leaves one pill stranded on its own line. */
.account-badges { display: inline-flex; align-items: center; gap: .35rem; flex-wrap: wrap; }
/* Explanatory line inside an account card: muted, normal weight. */
.account-note { color: var(--muted); font-size: .85rem; line-height: 1.5; }
/* The credential fields and their connect button as one block. */
.account-connect { display: grid; gap: .85rem; }
.account-connect label { display: grid; gap: .4rem; }
.account-meta { display: flex; justify-content: space-between; align-items: center; gap: .75rem; }
.provider-row {
    display: grid;
    grid-template-columns: 32px 1fr auto;
    gap: .65rem;
    align-items: center;
}
.provider-row.enabled { border-left: 3px solid var(--accent-soft); }
.provider-row.disabled { opacity: .55; }
.provider-row.builtin { border-left: 3px solid var(--border); }
.provider-icon { font-size: 1.3rem; line-height: 1; }
/* Connection rows (dashboard): icon column, flexible info, right pill. */
.connection-row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    gap: .75rem;
    align-items: center;
    padding: .75rem;
    border-radius: 8px;
    background: var(--surface-3);
    border-bottom: 1px solid rgba(39, 39, 42, .4);
}
.connection-row small { font-size: .78rem; color: var(--muted); margin: 0; }
.connection-row .pill { justify-self: end; }
.connection-row.enabled { border-left: 3px solid var(--accent-soft); }
.connection-group .connection-row:last-child { border-bottom: 0; }
.connection-icon { color: var(--muted); flex-shrink: 0; }
.connection-info { min-width: 0; }
.connection-info small {
    display: block;
    color: var(--muted);
    font-size: .78rem;
    line-height: 1.4;
    overflow-wrap: anywhere;
    word-break: normal;
}
.provider-info { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.provider-info small { font-size: .78rem; color: var(--muted); white-space: normal; }
.provider-tags,
.provider-platforms { display: flex; flex-wrap: wrap; gap: .25rem; margin-top: .2rem; }
.provider-qualities { display: flex; gap: .25rem; flex-wrap: wrap; }
/* Shared badge base for small capability/fact chips (playlist cards,
   plugin quality lines). Shape tweaks live in the owning page's
   scoped css so the two contexts stay independent. */
.quality-badge {
    font-size: .72rem;
    padding: .18rem .55rem;
    background: var(--surface-2);
    color: var(--muted);
    border: 1px solid var(--border);
}
.quality-badge.warn {
    color: var(--warning);
    background: var(--warning-soft);
    border-color: rgba(251, 191, 36, .25);
}
:root[data-theme="light"] .quality-badge.warn { color: #92400e; }
.pill.outline {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--muted);
    font-size: .7rem;
}
.pill.outline.small { font-size: .65rem; padding: .05rem .35rem; }

/* Toggle switch */
.toggle-switch {
    position: relative;
    display: inline-block;
    width: 40px;
    height: 22px;
    flex-shrink: 0;
}
.toggle-switch input { opacity: 0; width: 0; height: 0; }
.toggle-slider {
    position: absolute;
    cursor: pointer;
    inset: 0;
    background: var(--surface-3);
    border: 1px solid var(--border-strong);
    border-radius: 22px;
    transition: .2s;
}
.toggle-slider::before {
    content: "";
    position: absolute;
    height: 16px;
    width: 16px;
    left: 2px;
    bottom: 2px;
    background: var(--muted);
    border-radius: 50%;
    transition: .2s;
}
.toggle-switch input:checked + .toggle-slider { background: var(--accent-soft); border-color: var(--accent-strong); }
.toggle-switch input:checked + .toggle-slider::before { transform: translateX(18px); background: var(--accent-strong); }
.panel-description { font-size: .85rem; color: var(--muted); font-weight: 400; margin: -.25rem 0 .75rem; }
.hint-box {
    padding: .8rem;
    border-radius: 8px;
    color: var(--muted);
    background: var(--surface-2);
    border: 1px solid var(--border);
}
/* Error-flavoured hint box for forms that validate inline. */
.hint-box.danger { border-color: var(--danger); }
.form-error { margin-top: .75rem; }
/* Partial-sync marker next to the last-synced line: warning color, no
   layout shift when absent. */
.sync-warn {
    color: var(--warning);
    font-weight: 600;
}
.mount-warning {
    display: flex;
    gap: .7rem;
    padding: .8rem;
    border-radius: 8px;
    color: var(--text);
    background: var(--warning-soft);
    border: 1px solid color-mix(in srgb, var(--warning) 28%, transparent);
    font-size: .85rem;
    line-height: 1.55;
}
.mount-warning-icon { color: var(--warning); flex-shrink: 0; margin-top: .1rem; }
.mount-warning code { color: var(--accent-text); }

/* Help tips: a question-mark button next to a feature or setting. Hover
   or keyboard focus shows the short explanation; clicking opens the
   matching page on docs.melodybridge.app, anchors included. */
.title-with-help { display: flex; align-items: center; gap: .45rem; }
.field-with-help { display: flex; align-items: flex-start; gap: .35rem; }
.field-with-help > label { flex: 1; min-width: 0; }
.field-with-help .help-tip { margin-top: .3rem; }
.toggle-with-help { display: flex; align-items: center; gap: .35rem; }
.toggle-with-help > label { flex: 1; min-width: 0; }
.help-tip {
    position: relative;
    display: inline-grid;
    place-items: center;
    width: 21px;
    height: 21px;
    flex-shrink: 0;
    border: 1px solid var(--border-strong);
    border-radius: 50%;
    background: var(--surface-2);
    color: var(--muted);
    text-decoration: none;
}
.help-tip:hover,
.help-tip:focus-visible { color: var(--accent-strong); border-color: var(--accent-strong); }
.help-tip-popup {
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    z-index: 400;
    display: none;
    width: min(300px, calc(100vw - 2rem));
    padding: .6rem .7rem;
    border: 1px solid var(--border-strong);
    border-radius: 8px;
    background: var(--surface-2);
    box-shadow: var(--shadow);
    color: var(--muted);
    font-size: .78rem;
    font-weight: 400;
    line-height: 1.5;
    text-align: left;
    white-space: normal;
}
.help-tip:hover .help-tip-popup,
.help-tip:focus-visible .help-tip-popup { display: block; }
.help-tip-more { display: block; margin-top: .3rem; color: var(--accent-strong); font-weight: 600; }
.help-tip-more svg { vertical-align: -2px; margin-left: .15rem; }
.empty-state {
    display: grid;
    place-content: center;
    justify-items: center;
    text-align: center;
    gap: .35rem;
    padding: 2.5rem 1.25rem;
    color: var(--muted-2);
    background: rgba(24, 24, 27, .35);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}
.empty-state .empty-icon { color: var(--muted-2); }
.empty-state .empty-title { font-size: .95rem; color: var(--text); }
.empty-state .empty-desc { font-size: .85rem; color: var(--muted-2); line-height: 1.5; }
.empty-state .empty-actions { margin-top: .5rem; display: flex; gap: .5rem; justify-content: center; }
:root[data-theme="light"] .empty-state { background: rgba(24, 24, 27, .03); }
.result-box {
    margin: 0;
    white-space: pre-wrap;
    overflow: auto;
    max-height: 360px;
    padding: 1rem;
    border-radius: 8px;
    color: var(--text);
    background: var(--bg);
    border: 1px solid var(--border);
}
.toast-preview {
    position: fixed;
    right: 1rem;
    bottom: 1rem;
    padding: .8rem .9rem;
    border-radius: 8px;
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
    box-shadow: var(--shadow);
}

/* Wizard modal */
.wizard-overlay {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: grid;
    place-items: center;
    background: rgba(0, 0, 0, .6);
    backdrop-filter: blur(4px);
}
.wizard-modal {
    width: min(580px, calc(100vw - 2rem));
    max-height: 85vh;
    display: flex;
    flex-direction: column;
    border: 1px solid var(--border);
    border-radius: 14px;
    background: var(--surface-raised);
    box-shadow: var(--shadow-raised), 0 24px 48px rgba(0, 0, 0, .3);
}
/* Modals that carry a table (account playlists): room for the action
   column instead of a squeezed scroll area. */
.wizard-modal.wide {
    width: min(880px, calc(100vw - 2rem));
}
/* Confirm dialogs share the wizard shell but stay compact. */
.wizard-modal.confirm-modal {
    width: min(440px, calc(100vw - 2rem));
}
/* Compact form modals (scan locations) sit between confirm and wide. */
.wizard-modal.narrow {
    width: min(480px, calc(100vw - 2rem));
}
.confirm-message {
    margin: 0 0 .9rem;
    font-size: .95rem;
    line-height: 1.5;
}
.wizard-header {
    display: flex;
    align-items: start;
    justify-content: space-between;
    gap: .75rem;
    padding: 1.25rem 1.25rem 0;
}
.wizard-header h2 { font-size: 1.15rem; }
.wizard-body {
    padding: 1.25rem;
    overflow-y: auto;
    flex: 1;
}
/* Every direct block in a modal body keeps the same rhythm; children
   with their own margin (the h3 section titles) keep that instead. */
.wizard-body > * + * { margin-top: .85rem; }
/* Section titles inside import/import wizards (Spotify / From a file…). */
.wizard-body h3 {
    font-size: .8rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--muted);
    margin: .25rem 0 .25rem;
}
.wizard-body h3:not(:first-child) { margin-top: 1.5rem; }
.wizard-footer {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: .75rem;
    padding: 1rem 1.25rem 1.25rem;
    border-top: 1px solid var(--border);
}
/* Wizard errors live outside the scrollable body, as a full-width first
   row of the footer, so the button that produced them is always in view. */
.wizard-footer .wizard-error { flex: 1 1 100%; margin: 0; }
.review-list {
    display: grid;
    gap: .6rem;
}
.review-list > div {
    padding: .55rem .7rem;
    border-radius: 6px;
    background: var(--surface-3);
    font-size: .9rem;
}
.log-entry {
    display: flex;
    gap: .65rem;
    align-items: start;
    padding: .65rem .75rem;
    border-radius: 8px;
    background: var(--surface-3);
    margin-bottom: .5rem;
}
.log-entry > div { min-width: 0; flex: 1; }
.log-entry strong { display: block; }
.log-entry p { margin: .15rem 0; font-size: .85rem; }
.log-entry small { font-size: .78rem; }
.job-meta {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: .25rem .75rem;
    margin-top: .35rem;
}
/* -- List layouts shared by Playlists and Sync jobs ----------------
   A page that can grow many entities offers two shapes: cards (the
   default) and one compact row per entity. The switch and the rows are
   shared so both pages stay visually identical. */
.card-size-control {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .1rem .15rem .1rem .55rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    color: var(--muted);
    min-height: 34px;
}
.card-size-control select {
    width: auto;
    min-width: 5.6rem;
    min-height: 30px;
    padding: .2rem 1.6rem .2rem .25rem;
    border: 0;
    background: transparent;
    color: var(--text);
    font: inherit;
    font-size: .82rem;
}
.card-size-control:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

.view-switch {
    display: inline-flex;
    gap: .15rem;
    padding: .15rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface-2);
}
.view-chip {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .32rem .6rem;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: var(--muted);
    font: inherit;
    font-size: .82rem;
    cursor: pointer;
}
.view-chip:hover { color: inherit; }
.view-chip.on { background: var(--surface-raised); color: inherit; }

.entity-rows { display: grid; gap: .5rem; margin-top: 1rem; }
.entity-row {
    display: flex;
    align-items: center;
    gap: .75rem;
    min-width: 0;
    padding: .5rem .65rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-raised);
}
.entity-row:hover { border-color: var(--border-strong); }
.entity-row-link {
    display: flex;
    align-items: center;
    flex: 1;
    gap: .75rem;
    min-width: 0;
    color: inherit;
    text-decoration: none;
}
.entity-row-cover {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 42px;
    height: 42px;
    overflow: hidden;
    border-radius: 8px;
    background: var(--surface-3);
    color: var(--muted);
}
.entity-row-cover img { width: 100%; height: 100%; object-fit: cover; }
.entity-row-main { flex: 1; display: grid; gap: .05rem; min-width: 0; }
.entity-row-main strong {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.entity-row-main small { color: var(--muted); }
.entity-row-state { display: flex; align-items: center; flex-wrap: wrap; gap: .3rem; }
.entity-row-meta {
    display: flex;
    gap: .5rem;
    color: var(--muted);
    font-size: .8rem;
    white-space: nowrap;
}
/* Row actions: keep buttons on one line, shrink to icons on phones. */
.entity-row-actions { display: flex; align-items: center; gap: .35rem; flex-wrap: wrap; }

/* -- List toolbar and selection -------------------------------- */
/* The quiet row above a list: count and sort on the left, layout and
   selection on the right. It keeps page-title actions and list controls
   from competing for the same line. */
.list-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    flex-wrap: wrap;
    margin: 1rem 0 .75rem;
}
.list-toolbar-left,
.list-toolbar-actions { display: flex; align-items: center; gap: .55rem; flex-wrap: wrap; min-width: 0; }
.list-count { color: var(--muted); font-size: .84rem; white-space: nowrap; }
.filter-chip.attention { display: inline-flex; align-items: center; gap: .35rem; }
.filter-chip.attention:disabled { opacity: .5; cursor: not-allowed; }
.filter-count {
    display: inline-grid;
    place-items: center;
    min-width: 18px;
    height: 18px;
    padding: 0 .3rem;
    border: 1px solid rgba(251, 191, 36, .25);
    border-radius: 999px;
    background: var(--warning-soft);
    color: var(--warning);
    font-size: .68rem;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}
.filter-chip.attention.active .filter-count {
    background: var(--accent);
    border-color: transparent;
    color: var(--accent-contrast);
}
.pin-mark { color: var(--accent-text); margin-right: .25rem; vertical-align: -1px; }
.list-toolbar + .content-grid,
.list-toolbar + .entity-rows,
.selection-bar + .content-grid,
.selection-bar + .entity-rows { margin-top: 0; }
.sort-control {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .1rem .15rem .1rem .55rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    color: var(--muted);
    min-height: 34px;
}
.sort-control select {
    width: auto;
    min-width: 8.5rem;
    min-height: 30px;
    padding: .2rem 1.6rem .2rem .25rem;
    border: 0;
    background: transparent;
    color: var(--text);
    font-size: .84rem;
    box-shadow: none;
}
.sort-control select:focus { box-shadow: none; }
.sort-control:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

.selection-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    flex-wrap: wrap;
    margin: 1rem 0 .75rem;
    padding: .55rem .7rem;
    border: 1px solid var(--accent);
    border-radius: var(--radius);
    background: color-mix(in srgb, var(--accent) 8%, var(--surface));
}
.selection-all { display: inline-flex; align-items: center; gap: .5rem; font-size: .88rem; font-weight: 600; }
.selection-all input { width: 17px; height: 17px; accent-color: var(--accent-strong); }
.selection-actions { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.danger-text { color: var(--danger); }
.danger-text:hover { color: var(--danger); border-color: rgba(251, 113, 133, .4); }

.link-button {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: 0;
    border: 0;
    background: none;
    color: var(--accent-text);
    font: inherit;
    font-size: .84rem;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
}
.link-button:hover { text-decoration: underline; }

/* Selection overlays: the card or row gets an accent edge, and the
   checkbox floats over the cover without hiding it. */
.playlist-card.selected,
.entity-row.selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent-soft); }
.entity-row.selecting { cursor: pointer; }
.row-select { width: 18px; height: 18px; flex: 0 0 auto; accent-color: var(--accent-strong); }
.select-check {
    position: absolute;
    top: .5rem;
    left: .5rem;
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    border-radius: 999px;
    border: 2px solid rgba(0, 0, 0, .22);
    background: rgba(255, 255, 255, .88);
    color: transparent;
    box-shadow: 0 1px 4px rgba(0, 0, 0, .25);
}
.select-check.on { background: var(--accent-strong); border-color: var(--accent-strong); color: var(--accent-contrast); }

/* -- Sync jobs ------------------------------------------------ */
.job-card { display: flex; flex-direction: column; gap: .7rem; }
.job-heading { min-width: 0; }
.job-heading h2 { margin: 0; font-size: 1.08rem; overflow: hidden; text-overflow: ellipsis; }
.job-source-line {
    display: flex;
    align-items: center;
    gap: .45rem;
    flex-wrap: wrap;
    color: var(--muted);
    margin-top: .1rem;
}
.job-source-link { color: var(--muted); text-decoration: none; }
.job-source-link:hover { color: var(--accent-text); text-decoration: underline; }
.target-chips { display: flex; flex-wrap: wrap; gap: .35rem; }
.target-chip {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    max-width: 100%;
    min-width: 0;
    padding: .2rem .5rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface-2);
    color: var(--muted);
    font-size: .74rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.target-chip-text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.target-inline {
    display: inline-flex;
    align-items: center;
    gap: .2rem;
    margin-left: 0;
    max-width: 100%;
    min-width: 0;
    color: var(--muted-2);
    white-space: nowrap;
}
.target-inline .icon { flex: 0 0 auto; }
.target-inline-text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.job-summary {
    margin: 0;
    color: var(--muted);
    font-size: .9rem;
    line-height: 1.45;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.job-progress { display: grid; gap: .3rem; }
.job-progress small { color: var(--muted-2); font-size: .75rem; }
.job-progress .progress-track { height: 5px; }
.job-progress.is-failed .progress-fill { background: var(--danger); }
.job-progress.is-warn .progress-fill { background: var(--warning); }
.job-progress.is-ok .progress-fill { background: linear-gradient(90deg, var(--accent), var(--success)); }
.job-card .job-meta {
    display: flex;
    gap: .35rem 1rem;
    flex-wrap: wrap;
    margin-top: .1rem;
    color: var(--muted-2);
}
.job-card .job-meta small { font-size: .78rem; }
.job-footer {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: .5rem;
    margin-top: auto;
    padding-top: .7rem;
    border-top: 1px solid var(--border);
}
.job-footer .card-menu { margin-left: auto; }

/* -- Account import and quick publish ------------------------- */
.section-title-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    flex-wrap: wrap;
}
.section-title-row h3 { margin: 0; }
.account-list-toolbar {
    display: flex;
    align-items: center;
    gap: .6rem;
    flex-wrap: wrap;
    margin: .75rem 0 .5rem;
}
.account-list-toolbar .btn-modern { margin-left: auto; }
.account-playlist-table .col-select { width: 2rem; }
.account-playlist-table tr.selected td { background: color-mix(in srgb, var(--accent) 6%, transparent); }
.account-playlist-table input[type=checkbox] { width: 17px; height: 17px; accent-color: var(--accent-strong); }
@media (max-width: 720px) {
    .table-wrap .account-playlist-table { min-width: 0; }
    .account-playlist-table .col-owner,
    .account-playlist-table .col-tracks { display: none; }
}
.import-results { display: grid; gap: .45rem; }
.import-result {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    padding: .6rem .7rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface-2);
}
.import-result > div { min-width: 0; display: grid; gap: .1rem; }
.import-result strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.import-result small { color: var(--muted); }
.publish-schedule { display: grid; gap: .25rem; }
.publish-schedule .form-grid { margin: 0; }

@media (max-width: 640px) {
    .entity-row-meta { display: none; }
    .entity-row-actions .btn-label { display: none; }
    .view-chip span { display: none; }
    .view-chip { padding: .38rem; }
    .list-toolbar { align-items: stretch; }
    .list-toolbar-left,
    .list-toolbar-actions { width: auto; }
    .list-toolbar-left.with-sort { flex: 1 1 100%; justify-content: space-between; }
    .list-toolbar-actions { margin-left: auto; }
    .sort-control { flex: 1 1 auto; }
    .sort-control select { flex: 1 1 auto; min-width: 0; width: 100%; }
    .selection-bar { align-items: stretch; }
    .selection-actions { width: 100%; }
    .selection-actions .btn-modern { flex: 1 1 auto; }
    .account-list-toolbar .btn-modern { margin-left: 0; width: 100%; }
    .import-result { align-items: stretch; flex-direction: column; }
    .import-result .btn-modern { justify-content: center; }
}
textarea {
    width: 100%;
    min-height: 40px;
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: .55rem .7rem;
    background: var(--bg);
    color: var(--text);
    outline: none;
    font-family: inherit;
    resize: vertical;
}
textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

/* -- Blazor reconnect dialog (markup lives in _Host.cshtml) -------- */
.components-reconnect-first-attempt-visible,
.components-reconnect-repeated-attempt-visible,
.components-reconnect-failed-visible,
.components-pause-visible,
.components-resume-failed-visible,
.components-rejoining-animation {
    display: none;
}
#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible,
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation,
#components-reconnect-modal.components-reconnect-paused .components-pause-visible,
#components-reconnect-modal.components-reconnect-paused .components-resume-failed-visible,
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible,
#components-reconnect-modal.components-reconnect-retrying,
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible,
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation,
#components-reconnect-modal.components-reconnect-failed,
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible {
    display: block;
}
#components-reconnect-modal {
    background: var(--surface-2);
    color: var(--text);
    border: 1px solid var(--border-strong);
    width: min(22rem, calc(100vw - 2rem));
    margin: 20vh auto;
    padding: 2rem;
    border-radius: var(--radius);
    box-shadow: var(--shadow);
}
#components-reconnect-modal::backdrop {
    background-color: rgba(0, 0, 0, .5);
}
.components-reconnect-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}
#components-reconnect-modal p { margin: 0; text-align: center; color: var(--muted); }
#components-reconnect-modal button {
    border: 0;
    background: var(--accent-strong);
    color: var(--accent-contrast);
    padding: .4rem 1.5rem;
    border-radius: 8px;
    font-weight: 700;
    cursor: pointer;
}
#components-reconnect-modal button:hover { background: var(--accent); }
.components-rejoining-animation { position: relative; width: 80px; height: 80px; }
.components-rejoining-animation div {
    position: absolute;
    border: 3px solid var(--accent);
    opacity: 1;
    border-radius: 50%;
    animation: components-rejoining-animation 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
}
.components-rejoining-animation div:nth-child(2) { animation-delay: -.5s; }
@keyframes components-rejoining-animation {
    0%, 4.9% { top: 40px; left: 40px; width: 0; height: 0; opacity: 0; }
    5% { top: 40px; left: 40px; width: 0; height: 0; opacity: 1; }
    100% { top: 0; left: 0; width: 80px; height: 80px; opacity: 0; }
}

#blazor-error-ui {
    display: none;
    position: fixed;
    right: 1rem;
    bottom: 1rem;
    z-index: 1000;
    padding: .85rem 3rem .85rem 1rem;
    border-radius: 8px;
    background: #7f1d1d;
    color: white;
    box-shadow: var(--shadow);
}
#blazor-error-ui .reload { color: white; font-weight: 700; margin-left: .75rem; }
#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: .85rem;
    top: .6rem;
    background: none;
    border: 0;
    color: var(--muted);
    font-size: .9rem;
    font-weight: 700;
    line-height: 1;
    padding: .25rem;
}
#blazor-error-ui .dismiss:hover { color: white; }
#blazor-error-ui .dismiss:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.valid.modified:not([type=checkbox]) { outline: 1px solid var(--success); }
.invalid { outline: 1px solid var(--danger); }
.validation-message { color: var(--danger); }
.blazor-error-boundary { background: #7f1d1d; padding: 1rem; color: white; border-radius: 8px; }
.blazor-error-boundary::after { content: "An error has occurred."; }

/* -- Playlists ------------------------------------------- */
/* Cards are divs, not links: only the cover and the title navigate,
   so the metadata lines stay plain text. */
.playlist-card { display: flex; flex-direction: column; gap: .6rem; }
.playlist-card h2 { font-size: 1.05rem; margin: 0; }
.playlist-card h2 a { color: var(--text); text-decoration: none; }
.playlist-card h2 a:hover { color: var(--accent-strong); text-decoration: underline; }
.playlist-card .eyebrow { font-size: .66rem; }
.playlist-grid {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
}
.playlist-grid .playlist-card { flex-direction: row; align-items: center; }
.playlist-grid .playlist-cover { aspect-ratio: 1; width: 88px; flex-shrink: 0; }
.playlist-cover {
    aspect-ratio: 1 / 1;
    width: 100%;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--surface-2);
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
}
.playlist-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.playlist-cover-placeholder { font-size: 2.6rem; color: var(--muted-2); }
.playlist-cover.small { width: 88px; aspect-ratio: 1; flex-shrink: 0; }
.playlist-header { display: flex; gap: 1.1rem; align-items: center; }
.playlist-header h1 { margin-bottom: .2rem; }
.playlist-header p { margin: 0; font-size: .95rem; }
.toggle-row { display: flex; align-items: center; gap: .6rem; }
.toggle-row input[type=checkbox] { width: 18px; height: 18px; accent-color: var(--accent-strong); }

/* Path fields: the input keeps the width and the optional browse button
   sits at its edge. Pages with their own scoped copy keep the same rule. */
.path-field { display: flex; align-items: center; gap: .5rem; min-width: 0; }
.path-field > input { flex: 1; min-width: 0; }

/* -- Modern table ---------------------------------------- */
.table-wrap { overflow-x: auto; position: relative; }
.table-pager {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    flex-wrap: wrap;
    padding: .65rem .25rem 0;
    color: var(--muted);
    font-size: .86rem;
}
.table-pager-buttons {
    display: flex;
    align-items: center;
    gap: .35rem;
    flex-wrap: wrap;
}
.table-pager-page {
    padding: 0 .35rem;
    color: var(--text);
    white-space: nowrap;
}
.modern-table { width: 100%; border-collapse: collapse; font-size: .92rem; }
.modern-table th {
    text-align: left;
    padding: .55rem .75rem;
    color: var(--muted-2);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .06em;
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
}
.modern-table td {
    padding: .6rem .75rem;
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
}
.modern-table tbody tr:hover { background: var(--surface-2); }
.modern-table td strong { font-weight: 600; }
.text-muted { color: var(--muted-2); }
/* File paths in table cells: clip, never blow up the layout. */
td.file-path {
    max-width: 16rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--font-mono);
    font-size: .78rem;
}

/* -- Result box ------------------------------------------ */
.result-box { padding: .75rem 1rem; border-radius: 8px; margin-bottom: 1rem; font-size: .92rem; }
.result-box.ok { background: var(--accent-soft); color: var(--accent-strong); border: 1px solid var(--accent); }
.result-box.error { background: var(--danger-soft); color: var(--danger); border: 1px solid var(--danger); }

/* Pill variants live once, near the base component. */

/* -- Shared search and log primitives ------------------------------ */
.flex-actions { display: flex; gap: .5rem; align-items: center; }
/* Action rows that close a form or a card: the primary action sits at the
   right edge, where the eye ends up after reading the fields. */
.flex-actions.end { justify-content: flex-end; }
.search-controls { display: flex; flex-direction: column; gap: .6rem; }
.search-row { display: flex; gap: .6rem; }
.search-input,
.search-provider-select {
    flex: 1;
    min-width: 0;
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: .55rem .7rem;
    background: var(--bg);
    color: var(--text);
    outline: none;
}
.search-input:focus, .search-provider-select:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.search-provider-select { flex: 0 0 180px; }
.qi-result { display: grid; gap: .5rem; }
.qi-item { display: flex; gap: .6rem; align-items: center; padding: .5rem .6rem; border-radius: 6px; background: var(--surface-2); }
/* The text column of a result/download row: takes the room, never
   forces the row wider than its card. */
.qi-grow { flex: 1; min-width: 0; }
.qi-icon { width: 22px; text-align: center; font-size: .95rem; }
.qi-icon.ok { color: var(--success); }
.qi-icon.err { color: var(--danger); }
.qi-icon.pending { color: var(--muted-2); }
.qi-status { min-width: 70px; }
.qi-provider { font-weight: 600; min-width: 90px; }
.qi-meta, .qi-path { color: var(--muted-2); font-size: .8rem; }
.qi-error { color: var(--danger); font-size: .8rem; }
.btn-icon { margin-right: .3rem; }
.btn-icon-only { border: 0; background: none; cursor: pointer; color: var(--muted); padding: .25rem .45rem; border-radius: 6px; }
.btn-icon-only:hover { background: var(--surface-2); color: var(--text); }
.btn-filter {
    border: 1px solid var(--border);
    background: none;
    color: var(--muted);
    padding: .25rem .7rem;
    border-radius: 999px;
    cursor: pointer;
    font-size: .8rem;
}
.btn-filter.active { background: var(--accent-soft); color: var(--accent-strong); border-color: var(--accent); }
.log-section { max-height: 420px; display: flex; flex-direction: column; }
.log-filters { display: flex; gap: .4rem; flex-wrap: wrap; margin-bottom: .6rem; }
.log-container { overflow-y: auto; display: flex; flex-direction: column; gap: .25rem; max-height: 300px; }
.log-line {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: .78rem;
    padding: .3rem .5rem;
    border-radius: 4px;
    background: var(--surface-2);
    display: flex;
    gap: .6rem;
    align-items: baseline;
}
.log-line.trace, .log-line.debug { color: var(--muted-2); }
.log-line.info { color: var(--text); }
.log-line.warn { color: var(--warning); }
.log-line.error, .log-line.critical { color: var(--danger); }
.log-time { color: var(--muted-2); white-space: nowrap; }
.log-cat { color: var(--accent-strong); white-space: nowrap; }
.log-msg { flex: 1; min-width: 0; word-break: break-word; white-space: pre-wrap; }
.log-detail { margin-top: .35rem; padding: .5rem; border-radius: 6px; background: var(--bg); font-size: .75rem; color: var(--muted); white-space: pre-wrap; }
.log-empty { color: var(--muted-2); padding: 1rem 0; text-align: center; }
.hint { font-size: .82rem; color: var(--muted-2); }

@media (max-width: 1100px) {
    .app-shell { grid-template-columns: 1fr; }
    /* Below tablet the sidebar becomes a compact top strip: brand, one
       wrapping row of nav pills, theme toggle. The old layout stacked a
       600px column of links above the content. */
    .app-sidebar {
        position: relative;
        height: auto;
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        align-items: center;
        overflow: visible;
        gap: .35rem .75rem;
        padding: .75rem 1rem;
        border-right: 0;
        border-bottom: 1px solid var(--border);
    }
    .brand-block { padding: 0; margin: 0; border-bottom: 0; flex: 0 0 auto; }
    /* Nav gets its own full-width row; brand and theme toggle share the
       first row. Phones scroll the row sideways instead of wrapping into
       three lines of pills. */
    .app-nav {
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        gap: .25rem;
        flex: 1 1 100%;
        order: 3;
        min-width: 0;
        overflow-y: visible;
        padding-bottom: .1rem;
    }
    .nav-section:not(.nav-mode-section) { display: contents; margin: 0; }
    .nav-section-header { display: none; }
    .app-nav .nav-link { flex: 0 0 auto; white-space: nowrap; min-height: 34px; padding: .4rem .65rem; font-size: .85rem; }
    .sidebar-footer { position: static; margin: 0 0 0 auto; padding: 0; border: 0; background: none; order: 2; }
    .app-content { width: 100%; }
    .hero-panel,
    .content-grid.two,
    .content-grid.three,
    .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 720px) {
    .app-content { padding: 1rem; }
    .hero-panel,
    .content-grid.two,
    .content-grid.three,
    .stat-grid,
    .form-grid { grid-template-columns: minmax(0, 1fr); }
    .page-title { display: block; }
    .page-title .topbar-actions {
        display: flex;
        justify-content: flex-start;
        gap: .5rem;
        margin-top: .85rem;
    }
    .page-title .topbar-actions > .btn-modern { flex: 1 1 auto; }
    .detail-header .detail-actions > .btn-modern { flex: 0 1 auto; }
    .provider-row { grid-template-columns: 32px 1fr auto; }
    .provider-qualities { display: none; }

    /* One-column playlist cards stay compact: the cover sits beside the
       text instead of swallowing a phone screen. */
    .entity-row { align-items: flex-start; }
    .entity-row-main small { white-space: normal; }
    .target-inline { margin-left: 0; }
    .job-card .job-meta { display: grid; gap: .2rem; }
    .job-footer .btn-modern { flex: 0 1 auto; }
}
/* -- Downloads page: waterfall rank numbers --------------------- */
.provider-rank {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 8px;
    background: color-mix(in srgb, var(--accent) 14%, transparent);
    color: var(--accent-strong, #7F5AF0);
    font-size: .78rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    flex: none;
}

/* -- PlaylistDetails: live download progress --------------------- */
.download-live {
    margin-top: .9rem;
    padding: .9rem 1rem;
    border: 1px solid var(--border, rgba(128, 128, 128, .25));
    border-radius: 12px;
    background: color-mix(in srgb, var(--accent) 6%, transparent);
}

.download-live-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: .75rem;
    margin-bottom: .55rem;
    font-size: .85rem;
}

.download-live-head span {
    color: var(--muted-2);
    font-variant-numeric: tabular-nums;
}

.progress-track {
    height: 6px;
    border-radius: 99px;
    background: color-mix(in srgb, var(--border, #888) 25%, transparent);
    overflow: hidden;
}

.progress-fill {
    height: 100%;
    border-radius: 99px;
    background: linear-gradient(90deg, var(--accent), var(--success, #2CB67D));
    transition: width .5s ease;
}

.download-live .qi-meta {
    margin-top: .5rem;
    font-size: .75rem;
    color: var(--muted-2);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ── Logs page ─────────────────────────────────────────────────── */
.filter-chips {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    margin-bottom: .9rem;
}

.filter-chip {
    border: 1px solid var(--border, rgba(128, 128, 128, .3));
    background: transparent;
    color: var(--muted-2);
    border-radius: 99px;
    padding: .22rem .8rem;
    font-size: .74rem;
    cursor: pointer;
    transition: all .15s ease;
}

.filter-chip:hover {
    color: var(--text, #eee);
    border-color: var(--accent);
}

.filter-chip.active {
    background: color-mix(in srgb, var(--accent) 18%, transparent);
    color: var(--accent-strong, #7F5AF0);
    border-color: var(--accent);
    font-weight: 600;
}

.log-error-banner {
    border-color: rgba(251, 113, 133, .4);
    margin-bottom: 1.2rem;
}

.log-error-head {
    display: flex;
    align-items: center;
    gap: .8rem;
    margin-bottom: .7rem;
}

.log-error-head .qi-icon {
    flex: none;
}

.log-error-head strong {
    display: block;
    color: var(--danger);
}

.log-error-head p {
    margin: 0;
    font-size: .78rem;
    color: var(--muted-2);
}

.log-error-head button {
    margin-left: auto;
    flex: none;
}

.log-row.clickable {
    cursor: pointer;
    grid-template-columns: 4.2rem minmax(6rem, 12rem) 1fr;
}

.logs-list {
    display: flex;
    flex-direction: column;
    max-height: 62vh;
    overflow-y: auto;
    border: 1px solid var(--border, rgba(128, 128, 128, .25));
    border-radius: 10px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: .74rem;
}

.log-row {
    display: grid;
    grid-template-columns: 4.2rem 4.2rem minmax(8rem, 16rem) 1fr auto;
    gap: .6rem;
    padding: .45rem .7rem;
    border-bottom: 1px solid color-mix(in srgb, var(--border, #888) 60%, transparent);
    align-items: baseline;
    line-height: 1.45;
}

.log-actions {
    display: inline-flex;
    gap: .05rem;
    align-self: center;
    opacity: .5;
    transition: opacity .15s ease;
}

.log-row:hover .log-actions,
.log-row:focus-within .log-actions { opacity: 1; }

.log-actions .icon-button {
    width: 26px;
    min-height: 26px;
    color: var(--muted);
}

.log-actions .icon-button:hover { color: var(--text); }

.log-row:last-child {
    border-bottom: none;
}

.log-row.err {
    background: var(--danger-soft);
}

.log-row.warn {
    background: var(--warning-soft);
}

.log-time {
    color: var(--muted-2);
    font-variant-numeric: tabular-nums;
}

.log-level {
    font-weight: 700;
}

.log-row.err .log-level {
    color: var(--danger);
}

.log-row.warn .log-level {
    color: var(--warning);
}

.log-row.info .log-level {
    color: var(--accent-strong, #7F5AF0);
}

.log-category {
    color: var(--muted-2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.log-message {
    white-space: pre-wrap;
    word-break: break-word;
}

/* Small inline busy indicator, shared by the source picker, plugin checks
   and the downloads overview. */
.spinner {
    flex: 0 0 auto;
    width: 14px;
    height: 14px;
    border: 2px solid var(--border-strong);
    border-top-color: var(--accent-strong);
    border-radius: 50%;
    animation: mb-spin .8s linear infinite;
}
@keyframes mb-spin { to { transform: rotate(360deg); } }

.logs-count {
    margin-top: .5rem;
    font-size: .72rem;
    color: var(--muted-2);
    text-align: right;
}

/* The stream renders 200 rows at a time; older ones wait behind this. */
.logs-more {
    position: sticky;
    bottom: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .6rem;
    padding: .6rem;
    background: var(--surface-1);
    border-top: 1px solid var(--border);
}

.logs-more span {
    font-size: .72rem;
    color: var(--muted-2);
}

/* On a phone the four-column log grid squeezed the message to a few
   pixels. Time and level stay on one line, the message gets its own
   full-width line. */
@media (max-width: 720px) {
    .log-row {
        grid-template-columns: 3.6rem max-content minmax(0, 1fr) auto;
    }
    .log-row.clickable {
        grid-template-columns: 3.6rem max-content minmax(0, 1fr);
    }
    .log-row .log-time { grid-column: 1; grid-row: 1; }
    .log-row .log-level { grid-column: 2; grid-row: 1; }
    .log-row .log-category { grid-column: 3; grid-row: 1; }
    .log-row .log-actions { grid-column: 4; grid-row: 1; }
    .log-row .log-message { grid-column: 1 / -1; grid-row: 2; }
    .logs-list { font-size: .8rem; }
    /* The banner head stacks: icon, text, then the action buttons, so the
       message keeps its width instead of a 70px column. */
    .log-error-head { flex-wrap: wrap; }
    .log-error-head > div { flex: 1 1 60%; }
    .log-error-head button { margin-left: 0; }
}

/* ── Home page: three-step workflow ────────────────────────────── */
.workflow-list {
    display: flex;
    flex-direction: column;
    gap: .6rem;
    margin-bottom: .9rem;
}

.workflow-step {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: .85rem 1rem;
    border: 1px solid var(--border, rgba(128, 128, 128, .25));
    border-radius: 12px;
    text-decoration: none;
    color: inherit;
    transition: border-color .15s ease, background .15s ease;
}

.workflow-step:hover {
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 5%, transparent);
}

.workflow-step.done {
    border-color: color-mix(in srgb, var(--success, #2CB67D) 45%, transparent);
}

.workflow-number {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 9px;
    background: color-mix(in srgb, var(--accent) 14%, transparent);
    color: var(--accent-strong, #7F5AF0);
    font-weight: 700;
    flex: none;
}

.workflow-step.done .workflow-number {
    background: color-mix(in srgb, var(--success, #2CB67D) 16%, transparent);
    color: var(--success, #2CB67D);
}

.workflow-step strong {
    display: block;
    margin-bottom: .15rem;
}

.workflow-step p {
    margin: 0;
    font-size: .82rem;
    color: var(--muted-2);
}

.workflow-step small {
    color: var(--accent-strong, #7F5AF0);
    font-size: .72rem;
}

.workflow-step.done small {
    color: var(--success, #2CB67D);
}

.workflow-arrow {
    margin-left: auto;
    color: var(--muted-2);
    flex: none;
}

/* ── Settings tabs ─────────────────────────────────────────────── */
.tab-nav {
    display: flex;
    gap: .35rem;
    border-bottom: 1px solid var(--border);
    margin-bottom: 1rem;
    overflow-x: auto;
}
.tab-link {
    border: 0;
    background: none;
    padding: .6rem .95rem;
    cursor: pointer;
    color: var(--muted);
    font-weight: 600;
    font-size: .9rem;
    border-bottom: 2px solid transparent;
    white-space: nowrap;
}
.tab-link:hover { color: var(--text); }
.tab-link.active { color: var(--accent-strong); border-bottom-color: var(--accent-strong); }

/* Base for icon-button pairs (plugins priority, track row actions).
   Page tweaks live in the scoped .razor.css of the page that uses them. */
.btn-group { display: inline-flex; gap: .25rem; }

/* ── Playlist card badges ───────────────────────────────────────── */
.playlist-cover { position: relative; }
.cover-badge {
    position: absolute;
    right: .5rem;
    bottom: .5rem;
    padding: .2rem .55rem;
    border-radius: 99px;
    font-size: .72rem;
    font-weight: 700;
    backdrop-filter: blur(6px);
    color: white;
}
.cover-badge.downloading { background: color-mix(in srgb, var(--accent) 85%, transparent); }
.cover-badge.paused { background: rgba(251, 191, 36, .9); }
.cover-badge.complete { background: rgba(52, 211, 153, .9); }
.cover-badge.partial { background: rgba(90, 100, 120, .85); }

/* ── Track row actions ──────────────────────────────────────────── */
.track-actions { white-space: nowrap; text-align: right; }
.track-actions .btn-modern { margin-left: .3rem; }
/* A row with more decision buttons than fit (a dedup pair plus Remove)
   wraps cleanly instead of clipping the last button. */
.track-actions .btn-group { flex-wrap: wrap; justify-content: flex-end; row-gap: .3rem; }

/* ── Quality picker (two selects side by side) ───────────────────── */
.quality-picker { display: flex; gap: 1rem; flex-wrap: wrap; }
.quality-picker label { flex: 1 1 180px; }

/* ── Wide toggle rows (Advanced page) ────────────────────────────── */
/* The base .toggle-switch is a 40px inline-block built for bare
   switches; the wide variant keeps that track but lays the label text
   out beside it instead of inside the 40px box. */
.toggle-switch.wide {
    display: flex;
    align-items: center;
    gap: .75rem;
    width: auto;
    cursor: pointer;
}
.toggle-switch.wide input { position: absolute; opacity: 0; width: 0; height: 0; }
/* position:relative kills the base inset sizing, so the track needs its
   40x22 box back or it collapses and the knob overlaps the label text. */
.toggle-switch.wide .toggle-slider { position: relative; flex-shrink: 0; width: 40px; height: 22px; }

/* ── Guided tour ────────────────────────────────────────────────── */
.tour-overlay {
    position: fixed;
    inset: 0;
    z-index: 200;
    /* Block the page while the tour runs: a stray click on a spotlit tab
       would navigate away and drop the tour's progress. */
    pointer-events: auto;
    cursor: default;
}
/* The final, selectorless stop has no spotlight hole: one flat dim keeps
   the page in the background while the card hands off to the checklist. */
.tour-dim {
    position: absolute;
    inset: 0;
    background: color-mix(in srgb, #000 62%, transparent);
}
.tour-spotlight {
    position: absolute;
    display: none;
    border: 2px solid var(--accent-strong);
    border-radius: var(--radius);
    box-shadow: 0 0 0 4000px color-mix(in srgb, #000 62%, transparent);
    transition: all .3s ease;
    pointer-events: none;
}
.tour-card {
    position: absolute;
    left: 50%;
    bottom: 2rem;
    transform: translateX(-50%);
    width: min(30rem, calc(100vw - 2rem));
    max-width: 30rem;
    padding: 1.1rem 1.25rem;
    border-radius: var(--radius);
    /* Opaque: the translucent surface let the page ghost through the copy. */
    background: var(--surface-2);
    border: 1px solid var(--border);
    box-shadow: var(--shadow);
    pointer-events: auto;
}
.tour-card h3 { margin: .2rem 0 .4rem; }
.tour-card p { margin: 0 0 .8rem; color: var(--muted); font-size: .92rem; }

/* ── Toasts ──────────────────────────────────────────────────────── */
.toast-stack {
    position: fixed;
    right: 1rem;
    bottom: 1rem;
    /* Below a wizard/modal: a sticky error must never cover the picker's
       Download button. The history panel still keeps the full list. */
    z-index: 90;
    display: grid;
    gap: .5rem;
    width: min(22rem, calc(100vw - 2rem));
    max-height: min(55vh, 28rem);
    overflow-y: auto;
    padding-left: .15rem;
}
.toast-item {
    display: flex;
    align-items: flex-start;
    gap: .6rem;
    padding: .7rem .9rem;
    border-radius: var(--radius);
    background: var(--surface);
    border: 1px solid var(--border);
    box-shadow: 0 6px 18px rgba(0,0,0,.35);
    font-size: .88rem;
    animation: toast-in .25s ease;
}
/* Error messages often carry long URLs; let the text wrap instead of
   pushing the action and close button past the edge of a phone. */
.toast-item > span {
    min-width: 0;
    overflow-wrap: anywhere;
}
.toast-item .toast-action { flex-shrink: 0; }
.toast-item.success { border-left: 3px solid var(--success, #2CB67D); }
.toast-item.warn { border-left: 3px solid var(--warning); }
.toast-item.error { border-left: 3px solid var(--danger); }
.toast-item.info { border-left: 3px solid var(--accent-strong); }
.toast-item .toast-close {
    margin-left: auto;
    border: 0;
    background: none;
    color: var(--muted);
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
}
.toast-action {
    margin-left: .35rem;
    padding: .1rem .45rem;
    border: 1px solid color-mix(in srgb, currentColor 25%, transparent);
    border-radius: 99px;
    color: var(--accent-text);
    font-size: .78rem;
    font-weight: 700;
    white-space: nowrap;
    text-decoration: none;
}
.toast-action:hover { background: var(--accent-soft); }

/* ── Notification history ─────────────────────────────────────────── */
.notification-panel {
    position: fixed;
    left: 1rem;
    bottom: 5rem;
    z-index: 320;
    width: min(23rem, calc(100vw - 2rem));
    max-height: min(32rem, calc(100vh - 7rem));
    display: grid;
    grid-template-rows: auto minmax(0, 1fr);
    overflow: hidden;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    background: var(--surface-raised);
    box-shadow: var(--shadow-raised);
}
.notification-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: .75rem;
    padding: .8rem .9rem .65rem;
    border-bottom: 1px solid var(--border);
}
.notification-head strong { display: block; }
.notification-head .flex-actions { align-items: center; }
.notification-list { overflow-y: auto; padding: .35rem; }
.notification-row {
    display: flex;
    align-items: flex-start;
    gap: .55rem;
    padding: .55rem .55rem;
    border-radius: 8px;
}
.notification-row + .notification-row { border-top: 1px solid var(--border); }
.notification-dot {
    width: 7px;
    height: 7px;
    flex-shrink: 0;
    margin-top: .4rem;
    border-radius: 50%;
    background: var(--accent-strong);
}
.notification-row.success .notification-dot { background: var(--success); }
.notification-row.warn .notification-dot { background: var(--warning); }
.notification-row.error .notification-dot { background: var(--danger); }
.notification-copy { display: grid; gap: .1rem; min-width: 0; flex: 1; }
.notification-copy span { font-size: .82rem; line-height: 1.4; overflow-wrap: anywhere; }
.notification-copy small { color: var(--muted-2); font-size: .68rem; font-variant-numeric: tabular-nums; }
.notification-action {
    margin-left: auto;
    flex-shrink: 0;
    color: var(--accent-text);
    font-size: .74rem;
    font-weight: 700;
    text-decoration: none;
    white-space: nowrap;
}
.notification-action:hover { text-decoration: underline; }
.notification-dismiss {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    margin-left: .1rem;
    width: 1.6rem;
    height: 1.6rem;
    padding: 0;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: var(--muted-2);
    cursor: pointer;
}
.notification-dismiss:hover {
    background: var(--surface-3);
    color: var(--foreground);
}

@media (max-width: 1100px) {
    .notification-panel {
        left: 1rem;
        right: 1rem;
        bottom: 1rem;
        width: auto;
        max-height: min(30rem, calc(100vh - 2rem));
    }
}
@keyframes toast-in {
    from { opacity: 0; transform: translateY(.5rem); }
    to { opacity: 1; transform: translateY(0); }
}


/* ── Import modal: one row per source, action on the right ────────── */
.import-options { display: grid; gap: .6rem; }
.import-option {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: .85rem 1rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
}
.import-option-main { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }
.import-option-main p { flex-basis: 100%; margin: 0; color: var(--muted); font-size: .85rem; line-height: 1.45; }
.import-option-main strong { font-size: .95rem; }
.import-option-action { flex-shrink: 0; }
@media (max-width: 640px) {
    .import-option { flex-direction: column; align-items: stretch; }
}

/* ── Connections profiles ─────────────────────────────────────── */
.profile-list { display: grid; gap: .6rem; margin-top: .75rem; }
.profile-row {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .7rem .9rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
}

/* InputFile renders a plain file input; let it sit next to buttons. */
input[type="file"].btn-modern {
    display: inline-flex;
    align-items: center;
    font-size: .85rem;
    color: var(--muted);
}
input[type="file"].btn-modern::file-selector-button {
    border: 1px solid var(--border);
    border-radius: 99px;
    background: var(--surface-2);
    color: var(--text);
    padding: .45rem .95rem;
    margin-right: .6rem;
    cursor: pointer;
    font: inherit;
}

/* ── Radio choice rows (dialogs with a keep-or-delete pick) ───────── */
.choice-list { display: grid; gap: .5rem; margin-top: .25rem; }
.choice-row {
    display: flex;
    align-items: flex-start;
    gap: .7rem;
    padding: .65rem .85rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    cursor: pointer;
}
.choice-row:hover { border-color: var(--border-strong); }
/* The global input rule is built for text fields: a radio needs its own
   box, or it stretches to a 40px full-width blob. */
.choice-row input[type="radio"] {
    width: 18px;
    height: 18px;
    min-height: 18px;
    margin: .15rem 0 0 0;
    padding: 0;
    flex-shrink: 0;
    accent-color: var(--accent-strong);
}
.choice-row > span { display: grid; gap: .1rem; flex: 1; min-width: 0; }
.choice-row strong { font-size: .9rem; }
.choice-row small { color: var(--muted); line-height: 1.35; }
/* ── Polish pass: toggles, labels, tables, action rows ────────────── */
/* Wide toggles (Advanced, Library): text never overlaps the switch.
   Label flexes, switch keeps its box, whole row is one click target. */
.toggle-switch.wide {
    display: flex;
    align-items: center;
    gap: .75rem;
    width: auto;
    min-height: 38px;
    margin-bottom: .5rem;
    cursor: pointer;
    user-select: none;
}
.toggle-switch.wide > span:last-child { flex: 1; min-width: 0; }

/* Plain checkbox rows (Playlists, SyncJobs): text sits beside the box,
   never under it, and the row does not eat taps meant for other links.
   .form-grid .toggle-row (0,2,0) must beat .form-grid label (0,1,1, display:grid),
   which otherwise stacks the checkbox above the text. */
.form-grid .toggle-row,
.toggle-row {
    display: flex;
    align-items: center;
    gap: .6rem;
    min-height: 38px;
    cursor: pointer;
    user-select: none;
}
.toggle-row span { flex: 1; min-width: 0; }

/* Two quality dropdowns side by side with breathing room; the guidance
   line below keeps its own space. */
.quality-picker { align-items: end; gap: 1.25rem; }
.quality-picker label { flex: 1 1 200px; min-width: 0; }
/* The preset blurb always sits under the select, never beside it: a
   half-line of text next to a dropdown reads as a second field. The
   grid gap below owns the spacing, so drop the bottom margin. */
.quality-picker .panel-description { flex-basis: 100%; margin-bottom: 0; }

/* Auto-save state pill in the panel header: quiet by design, colored
   only while it means something (saving/saved/failed). */
.save-state {
    font-size: .75rem;
    font-weight: 500;
    padding: .15rem .6rem;
    border-radius: 999px;
    border: 1px solid transparent;
    color: var(--muted-2);
    white-space: nowrap;
}
.save-state.saving { color: var(--accent); border-color: var(--accent-soft); background: var(--accent-soft); }
.save-state.saved { color: var(--success); border-color: rgba(52, 211, 153, .25); background: var(--success-soft); }
.save-state.failed { color: var(--danger); border-color: rgba(251, 113, 133, .25); background: var(--danger-soft); }

/* The advanced quality filters are a sub-setting of the quality dropdown:
   indented, framed, and quieter than the surrounding form, so they read
   as belonging to the select above them, not as a peer field. */
.advanced-quality {
    flex-basis: 100%;
    margin: .25rem 0 0 1.25rem;
    padding: .75rem .9rem;
    border-left: 3px solid var(--accent);
    background: var(--surface-2);
    border-radius: 0 .5rem .5rem 0;
}
.advanced-quality .hint-box { margin-bottom: .75rem; font-size: .82rem; }

/* Why a track failed, in small quiet text under the status pill; the
   full story stays available on the pill's hover. */
.fail-note { font-size: .75rem; color: var(--muted-2); margin-top: .15rem; max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── Track table: stable columns, sortable headers, pill status cells ── */
/* Fixed layout plus explicit col widths: rows cannot wobble, borders
   line up, and the actions column never gets squeezed off screen. The
   fixed widths stay lean so the title and artist columns keep real room
   at laptop widths: when they outgrow the table, fixed layout shrinks
   the percentage columns first and those two collapse. */
.track-table { table-layout: fixed; }
.track-table .col-pos { width: 2.25rem; }
.track-table .col-title { width: 19%; }
.track-table .col-artist { width: 15%; }
.track-table .col-num { width: 4.25rem; }
.track-table .col-format { width: 4.25rem; }
.track-table .col-status { width: 7rem; }
.track-table .col-file { width: 9rem; }
/* Wide enough for one button line: Choose source plus the icon-sized
   Remove, and a review row's Keep / Retry / Remove trio fits too. */
.track-table .col-actions { width: 12.5rem; }
/* Remove stays icon-only inside the track table (its tooltip and
   aria-label carry the word): the row actions then fit on one line and
   the title and artist columns keep real room. */
.track-table .track-actions button[aria-label="Remove"] .btn-label { display: none; }

/* Row actions are pinned to the right edge of the scroll container: the
   table is wider than most laptop windows, and the per-track buttons must
   never need a sideways hunt. The opaque fill covers the cells that scroll
   underneath (the card surface itself is translucent in dark theme). */
.track-table th.col-actions,
.track-table td.track-actions {
    position: sticky;
    right: 0;
    background: var(--bg);
    border-left: 1px solid var(--border);
}
:root[data-theme="light"] .track-table th.col-actions,
:root[data-theme="light"] .track-table td.track-actions { background: var(--surface); }
.modern-table tbody tr:hover td.track-actions { background: var(--surface-2); }

/* Mid-size windows: the percentage columns would collapse once the fixed
   columns outgrow the table, so the text columns get real pixel widths
   and the table scrolls under the pinned actions instead. */
@media (max-width: 1300px) {
    .track-table .col-title { width: 11rem; }
    .track-table .col-artist { width: 8rem; }
}

/* Narrow screens: drop the secondary audio columns and shorten the row
   actions to their icons. The pinned column then stays small and the
   title and artist keep readable width inside the 640px table floor. */
@media (max-width: 720px) {
    /* The table is as wide as its columns: no leftover space is spread
       over the text columns, so the px widths below hold exactly. The
       extra element in the selector beats the shared 640px floor. */
    .table-wrap table.track-table { min-width: 0; }
    .track-table .col-size,
    .track-table .col-bitrate,
    .track-table .col-rate,
    .track-table .col-format,
    .track-table .col-file { display: none; }
    .track-table .col-title { width: 7.5rem; }
    .track-table .col-artist { width: 5rem; }
    /* Room for two icon buttons per line, so a three-button row wraps to
       two lines instead of stacking one per line. */
    .track-table .col-actions { width: 6.5rem; }
    .track-table .track-actions .btn-label { display: none; }
    .track-table .track-actions .btn-modern { padding: .35rem .4rem; margin-left: .25rem; }
}

/* Denser cells: the row action buttons need the width more than the
   cells need the padding. */
.track-table td, .track-table th { padding-left: .5rem; padding-right: .5rem; }
.track-table .track-actions .btn-modern { padding: .3rem .45rem; }

/* Numeric columns hug their numbers, headers included. */
.track-table th.num, .track-table td.num { text-align: right; }
.track-table th.num .th-sort { justify-content: flex-end; }

/* Sortable header: a real button so keyboard and screen readers work. */
.track-table .th-sort {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    cursor: pointer;
}
.track-table .th-sort:hover { color: var(--text); }
.track-table .sort-arrow { font-size: .7rem; line-height: 1; }

/* Title, artist and File cells clip long values instead of stretching the row. */
.track-table .cell-title, .track-table .cell-artist { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.track-table .cell-file span { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
/* Archive copies: a second, quieter filename under the primary one.
   Same clip rules, dimmer color, so the row keeps one visual line. */
.track-table .archive-chip {
    display: block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: .72rem;
    color: var(--muted-2);
    margin-top: .1rem;
}
/* Status cells: pill plus error note stack without stretching the row. */
.track-table .cell-status { line-height: 1.35; }
.track-table .pill-tight { padding: .05rem .45rem; min-height: 18px; }
.track-table .empty-row { text-align: center; padding: 1.5rem .75rem; color: var(--muted-2); }

/* Screen-reader-only text: the actions header is unlabeled on purpose. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* ── Playlist detail action bar ── */
/* The action group stays one horizontal row and wraps below the title
   block on narrow screens instead of overflowing it. */
.detail-header { align-items: flex-start; }
.detail-actions {
    flex-wrap: wrap;
    justify-content: flex-end;
    row-gap: .5rem;
}
@media (max-width: 900px) {
    .detail-header { flex-direction: column; }
    .detail-actions { justify-content: flex-start; }
}

/* Form labels: stacked text over input with enough vertical rhythm. */
.form-grid label { margin-bottom: .35rem; }

/* Placeholders are suggestions, not values: visibly lighter than typed text. */
input::placeholder, textarea::placeholder { color: var(--muted-2, #8a8f98); opacity: 1; }

/* Action rows: buttons plus adjacent description text (Settings test
   results, PlaylistDetails source link) get honest spacing. */
.flex-actions { gap: .75rem; flex-wrap: wrap; }
.flex-actions.spaced { margin-top: .5rem; }
.flex-actions .text-muted,
.flex-actions .hint {
    align-self: center;
    margin-left: .35rem;
    font-size: .85rem;
}

/* Panel header action area: a lone button never hugs the heading. */
.panel-header > .flex-actions { margin-left: auto; }

/* Wide data tables (PlaylistDetails tracks, Library, Playlists, Home):
   a floor width keeps columns readable; .table-wrap scrolls the rest. */
.table-wrap .modern-table { min-width: 640px; }

/* Compact variant (dashboard sync runs): the panel is narrow, so the
   cells wrap and the date stays on one line instead of clipping. */
.table-wrap .modern-table.compact { min-width: 0; }
.modern-table.compact th,
.modern-table.compact td { white-space: normal; padding: .5rem .55rem; }
.modern-table.compact .nowrap { white-space: nowrap; }
@media (max-width: 720px) {
    /* The date column is the first to go when space runs out; the sync
       jobs page keeps the full run history. */
    .modern-table.compact .col-when { display: none; }
}

/* Toast preview on Advanced keeps clear of the panel edge. */
.toast-preview { z-index: 300; max-width: min(24rem, calc(100vw - 2rem)); }

/* ── Wizard & step lists ─────────────────────────────────────────── */
/* Boxed wide toggles inside wizard bodies read as a list of choices
   instead of floating switches; tokens follow the active theme. */
.wizard-body .toggle-switch.wide {
    padding: .55rem .8rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface-2);
    margin-bottom: .5rem;
}

/* ── Skeleton loaders: shown while lists and grids fetch ───────── */
.skeleton {
    background: linear-gradient(90deg, rgba(39, 39, 42, .5) 25%, rgba(63, 63, 70, .6) 50%, rgba(39, 39, 42, .5) 75%);
    background-size: 200% 100%;
    animation: skeleton-shimmer 1.4s ease-in-out infinite;
    border-radius: 6px;
}
:root[data-theme="light"] .skeleton {
    background: linear-gradient(90deg, #e4e4e7 25%, #d4d4d8 50%, #e4e4e7 75%);
    background-size: 200% 100%;
}
@keyframes skeleton-shimmer {
    from { background-position: 200% 0; }
    to { background-position: -200% 0; }
}
.skeleton-line { height: 12px; border-radius: 999px; margin: .4rem 0; }
.skeleton-line.w-60 { width: 60%; }
.skeleton-line.w-40 { width: 40%; }
.skeleton-card { height: 96px; border-radius: var(--radius); }
.skeleton-grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
.skeleton-row { display: grid; gap: 1rem; grid-template-columns: 2rem 3fr 2fr 1fr 1fr auto; padding: .6rem .75rem; }
.skeleton-cell { height: 14px; }
.skeleton-block { display: block; }

/* Profile row: name, pills and url on the left, actions right. */
.profile-main { flex: 1; min-width: 0; }
.profile-url {
    display: block;
    color: var(--muted);
    font-size: .85rem;
    margin-top: .15rem;
    word-break: break-all;
}

/* Pending-edit state next to the Save button (Settings, Advanced): the
   title row is sticky there, so the save action stays reachable. */
.save-state.pending { color: var(--warning); border-color: color-mix(in srgb, var(--warning) 25%, transparent); background: var(--warning-soft); }

/* Scrollable regions get the app's focus ring, not the UA default. */
.table-wrap:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* Advisory path/preset warnings: yellow, never mistaken for errors. */
.text-warn { color: var(--warning); font-weight: 600; }

/* Accounts tab pills sit inline in their card, not stretched edge to edge. */
.account-card .pill { justify-self: start; }

/* Tabs wrap on phones instead of scrolling sideways with hidden sections. */
@media (max-width: 720px) {
    .tab-nav { flex-wrap: wrap; }
}

/* Icon sizing inside buttons and rows keeps text alignment stable. */
svg.icon { flex-shrink: 0; }


/* Phones: keep the two columns that decide what to do next (status and
   actions) ahead of the secondary artist and row number. The title takes
   the rest; an artist can be read on the playlist or source page. */
@media (max-width: 560px) {
    .track-table .col-pos,
    .track-table .col-position,
    .track-table .col-artist,
    .track-table .col-duration { display: none; }
    .track-table .col-title { width: auto; }
    .track-table .col-status { width: 6.5rem; }
    .track-table .col-actions { width: 6rem; }
}
