/* TH.ONE Faya: the one stylesheet of every server-rendered page. Served at /ui.css under a
   URL that changes with the content. No @import, no font, no image: nothing third-party. */

/* --- Base: tokens, page shell, navigation, controls, badges ---
   Colors are custom properties. --on-accent and --on-err are the text color on the accent and
   error fills; --accent-ink and --err-ink the text on their soft tints (badges); --field is the
   border of a control, at least 3:1 against its surface. Every pair is checked by
   tests/test_web_page.py in both themes. */
:root { color-scheme: light dark; --bg: #f4f6f8; --card: #fff; --ink: #0f1a22;
  --muted: #55626e; --line: #dde3e8; --field: #7d8c99; --accent: #0b6f78; --on-accent: #fff;
  --accent-soft: #e2f1f2; --accent-ink: #075a62; --err: #a3202f; --on-err: #fff;
  --err-soft: #fbe7ea; --err-ink: #8f1a28; --r-s: 6px; --r-m: 10px; --r-l: 16px; --hit: 44px;
  --shadow: 0 1px 2px rgb(15 26 34 / .05), 0 12px 32px rgb(15 26 34 / .07); }
@media (prefers-color-scheme: dark) { :root { --bg: #0a1117; --card: #111b23; --ink: #e7eef2;
  --muted: #9fadb8; --line: #22313b; --field: #6d7f8c; --accent: #4fc1ca;
  --on-accent: #0b1319; --accent-soft: #12303a; --accent-ink: #8adbe1; --err: #ff8f9b;
  --on-err: #0b1319; --err-soft: #3a1a20; --err-ink: #ffb3bb; --shadow: none; } }
@media (prefers-contrast: more) { :root { --muted: var(--ink); --line: var(--field); } }
*, ::before, ::after { box-sizing: border-box; }
body { margin: 0; min-height: 100vh; min-height: 100svh; display: flex; flex-direction: column;
  background: var(--bg); color: var(--ink); -webkit-font-smoothing: antialiased;
  font: 16px/1.55 ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  padding-inline: max(16px, env(safe-area-inset-left)) max(16px, env(safe-area-inset-right));
  padding-block-end: env(safe-area-inset-bottom); }
.mark { font-weight: 700; letter-spacing: -.01em; color: var(--ink); text-decoration: none; }
.mark span { color: var(--accent); }
.mark .full, .mark .short { color: var(--ink); }
.mark .full span { color: var(--accent); }
.skip { position: absolute; inset-inline-start: max(8px, env(safe-area-inset-left));
  inset-block-start: -64px; z-index: 30;
  padding: 10px 16px; border-radius: var(--r-m); background: var(--card); color: var(--ink);
  border: 1px solid var(--field); }
.skip:focus { inset-block-start: 8px; }
/* Signed-in shell: one nav, three shapes by window width (tab bar, rail from 600 px, sidebar
   from 840 px). The links never change, only how they are laid out. Leaving the app is an
   action, not a place, so it sits outside the nav: at the top on a phone, at the foot of the
   rail and the sidebar. */
:root { --tab: 56px; --rail: 80px; --side: 248px; --inset-l: env(safe-area-inset-left);
  --inset-r: env(safe-area-inset-right); --inset-b: env(safe-area-inset-bottom);
  scroll-padding-block-end: calc(var(--tab) + var(--inset-b) + 16px); }
body.app { padding: 0; display: block; }
.side { display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: max(14px, env(safe-area-inset-top)) max(16px, var(--inset-r)) 6px
    max(16px, var(--inset-l)); }
.side .mark { font-size: 1.125rem; }
.side .short { display: none; }
.side nav { position: fixed; inset: auto 0 0; z-index: 20; display: grid;
  grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); background: var(--card);
  border-block-start: 1px solid var(--line);
  padding: 0 var(--inset-r) var(--inset-b) var(--inset-l); }
.side nav a, .side .exit { position: relative; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 2px; min-block-size: var(--tab);
  min-inline-size: 0; padding: 6px 4px; color: var(--muted); text-decoration: none;
  font-size: .75rem; line-height: 1.2; text-align: center; }
.side nav a span, .side .exit span { min-inline-size: 0; overflow-wrap: anywhere; hyphens: auto; }
.side .exit { flex-direction: row; gap: 6px; min-block-size: 44px; padding-inline: 8px;
  font-size: .875rem; border-radius: var(--r-m); }
.side svg { inline-size: 24px; block-size: 24px; fill: none; stroke: currentColor;
  stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; flex: none; }
.side nav a:focus-visible, .side .exit:focus-visible { outline-offset: -4px; }
@media (hover: hover) {
  .side nav a:hover, .side .exit:hover { color: var(--ink); background: var(--accent-soft); } }
.side nav a[aria-current] { color: var(--ink); font-weight: 600; }
.side nav a[aria-current]::before { content: ""; position: absolute; inset: 0 22% auto;
  block-size: 3px; border-radius: 0 0 3px 3px; background: var(--accent); }
.side nav a[aria-current] svg { color: var(--accent); }
body.app > main { container-type: inline-size; min-width: 0; padding: 8px max(16px, var(--inset-r))
  calc(var(--tab) + var(--inset-b) + 32px) max(16px, var(--inset-l)); }
body.app > main:focus { outline: 0; }
body.app > main > * { max-width: 960px; margin-inline: auto; }
@media (max-height: 480px) { :root { --tab: 44px; } .side nav a { flex-direction: row; gap: 6px; } }
@media (min-width: 600px) {
  :root { --rail-w: calc(var(--rail) + var(--inset-l)); scroll-padding-block-end: 16px; }
  body.app { padding-inline-start: var(--rail-w); }
  .side { position: fixed; inset: 0 auto 0 0; z-index: 20; inline-size: var(--rail-w);
    flex-direction: column; align-items: stretch; justify-content: flex-start; gap: 8px;
    padding: max(16px, env(safe-area-inset-top)) 4px 16px max(4px, var(--inset-l));
    overflow-y: auto; overscroll-behavior: contain;
    background: var(--card); border-inline-end: 1px solid var(--line); }
  .side .mark { text-align: center; font-size: 1rem; }
  .side .full { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap; }
  .side .short { display: inline; }
  .side nav { position: static; display: flex; flex-direction: column; flex: 1; gap: 4px;
    padding: 0; border: 0; background: none; }
  .side nav a, .side .exit { flex-direction: column; border-radius: var(--r-m);
    min-block-size: 56px; font-size: .75rem; padding: 6px 4px; }
  .side nav a[aria-current] { background: var(--accent-soft); }
  .side nav a[aria-current]::before { inset: 22% auto 22% 0; inline-size: 3px; block-size: auto;
    border-radius: 0 3px 3px 0; }
  body.app > main { padding: 24px max(24px, var(--inset-r)) calc(40px + var(--inset-b)) 24px; }
}
@media (min-width: 840px) {
  :root { --side-w: calc(var(--side) + var(--inset-l)); }
  body.app { padding-inline-start: var(--side-w); }
  .side { inline-size: var(--side-w); padding-inline: max(12px, var(--inset-l)) 12px; }
  .side .mark { text-align: start; padding: 4px 12px 12px; font-size: 1.25rem; }
  .side .full { position: static; inline-size: auto; block-size: auto; overflow: visible;
    clip-path: none; white-space: normal; }
  .side .short { display: none; }
  .side nav a, .side .exit { flex-direction: row; justify-content: flex-start; gap: 12px;
    padding: 8px 12px; font-size: .9375rem; min-block-size: 44px; text-align: start; }
  body.app > main { padding: 32px max(40px, var(--inset-r)) calc(48px + var(--inset-b)) 40px; }
}
main.center { flex: 1; display: grid; place-items: center; padding-block: 24px; }
.shell { display: grid; gap: 20px; width: min(440px, 100%); }
.shell > .mark, .brand .mark { font-size: 1.25rem; }
.brand .lead, .brand .points, .brand .sample { display: none; }
@media (min-width: 840px) {
  .shell.with-brand { width: min(980px, 100%); grid-template-columns: minmax(0, 1fr) 440px;
    gap: 64px; align-items: center; }
  .brand .mark { font-size: 1.75rem; }
  .brand .lead { display: block; margin-top: 16px; font-size: 1.5rem; line-height: 1.35;
    color: var(--ink); letter-spacing: -.02em; font-weight: 600; }
  .brand .sample { display: grid; gap: 12px; margin-top: 28px; padding: 16px 18px;
    background: var(--card); border: 1px solid var(--line); border-radius: var(--r-m);
    max-width: 420px; }
  .sample-head, .sample-foot { display: flex; justify-content: space-between; gap: 12px;
    font-size: .8125rem; color: var(--muted); font-variant-numeric: tabular-nums; }
  .sample-head b { color: var(--ink); font-weight: 600; }
  .brand .points { display: grid; gap: 10px; margin: 24px 0 0; padding: 0; list-style: none;
    color: var(--muted); font-size: .9375rem; }
  .brand .points li { padding-inline-start: 18px; position: relative; }
  .brand .points li::before { content: ""; position: absolute; inset-inline-start: 0;
    top: .7em; width: 8px; height: 2px; background: var(--accent); }
}
.segments { display: flex; gap: 4px; }
.segments span { flex: 1; height: 8px; border-radius: 2px; background: var(--line); }
.segments span.on { background: var(--accent); }
.segments span.now { background: var(--accent-soft); box-shadow: inset 0 0 0 1px var(--accent); }
.card { background: var(--card); border: 1px solid var(--line); border-radius: var(--r-l);
  box-shadow: var(--shadow); padding: 28px; width: 100%; display: grid; gap: 14px; }
h1 { margin: 0; font-size: 1.375rem; line-height: 1.25; letter-spacing: -.015em;
  font-weight: 650; }
p { margin: 0; color: var(--muted); font-size: .9375rem; }
label { font-size: .875rem; font-weight: 600; }
.card { position: relative; }
.card > p:empty { position: absolute; }
::placeholder { color: var(--muted); opacity: 1; }
input, select { font: inherit; padding: 10px 12px; border: 1px solid var(--field);
  border-radius: var(--r-m); background: var(--card); color: inherit; min-width: 0; }
input:hover, select:hover { border-color: var(--ink); }
button { font: inherit; font-weight: 600; padding: 10px 16px; border: 0; cursor: pointer;
  border-radius: var(--r-m); background: var(--accent); color: var(--on-accent);
  min-block-size: 40px; }
button:hover, a.btn:hover, a.dl:hover { filter: brightness(1.08); }
button:active, a.btn:active { transform: translateY(1px); }
a.btn { display: flex; align-items: center; justify-content: center; text-align: center;
  text-decoration: none; font: inherit; font-weight: 600; padding: 10px 16px;
  border-radius: var(--r-m); background: var(--accent); color: var(--on-accent);
  min-block-size: 40px; }
a.btn.secondary { background: transparent; color: var(--ink); border: 1px solid var(--field); }
.badge { display: inline-flex; align-items: center; gap: 6px; padding: 2px 10px;
  border-radius: 999px; font-size: .75rem; font-weight: 600; }
.badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; }
@media (forced-colors: active) { .badge { border: 1px solid CanvasText; }
  .badge::before { forced-color-adjust: none; background: CanvasText; } }
.sr { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; }
.badge.active { background: var(--accent-soft); color: var(--accent-ink); }
.badge.suspended { background: var(--err-soft); color: var(--err-ink); }
.badge.suspended::before { border-radius: 1px; transform: rotate(45deg); }
.err { color: var(--err); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
button[aria-busy="true"] { pointer-events: none; cursor: progress; }
button[aria-busy="true"]::before { content: ""; display: inline-block; width: 1em; height: 1em;
  margin-inline-end: .55em; vertical-align: -.15em; border: 2px solid currentColor;
  border-inline-end-color: transparent; border-radius: 50%; animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(1turn); } }
@media (prefers-reduced-motion: reduce) {
  button[aria-busy="true"]::before { animation: none; border-inline-end-color: currentColor;
    opacity: .55; }
  button:active, a.btn:active { transform: none; } }
@media (pointer: coarse) {
  input, button, select, a.btn, a.dl, form.inline button { min-block-size: var(--hit); }
  .side .mark { display: inline-flex; align-items: center; min-block-size: var(--hit); } }
@media (forced-colors: active) { button, a.btn, a.dl { border: 1px solid ButtonText; }
  .card { border: 1px solid CanvasText; } .segments span { forced-color-adjust: none; }
  .side nav a[aria-current] { text-decoration: underline 2px; text-underline-offset: 6px; } }

/* --- Downloads: job cards --- */
.page-head { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between;
  gap: 12px; }
.page-head > div { flex: 1 1 20rem; max-inline-size: 60ch; }
.page-head h1 { margin-bottom: 4px; }
.jobs { list-style: none; margin: 20px 0 0; padding: 0; display: grid; gap: 12px; }
.job { display: grid; gap: 10px; padding: 16px; background: var(--card);
  border: 1px solid var(--line); border-radius: var(--r-m); }
.job-head { display: flex; flex-wrap: wrap; align-items: start; justify-content: space-between;
  gap: 8px 12px; }
.job-head .badge { flex: none; white-space: nowrap; }
.job h2 { margin: 0; font-size: 1rem; line-height: 1.35; font-weight: 600;
  overflow-wrap: anywhere; }
.job-meta { font-size: .8125rem; font-variant-numeric: tabular-nums; }
.job progress { inline-size: 100%; block-size: 8px; accent-color: var(--accent); }
.job a.btn { justify-self: stretch; }
.job .segments { display: grid; grid-template-columns: repeat(auto-fill, minmax(10px, 1fr));
  gap: 4px; }
.job .segments span { block-size: 8px; background: transparent;
  box-shadow: inset 0 0 0 1px var(--field); }
.job .segments span.on { background: var(--accent); box-shadow: none; }
.job .segments span.now { background: var(--accent-soft);
  box-shadow: inset 0 0 0 2px var(--accent); }
.job .segments span.skip { align-self: center; block-size: 4px; background: var(--muted);
  box-shadow: none; }
.job .segments span.bad { background: repeating-linear-gradient(135deg, var(--err) 0 3px,
  transparent 3px 6px); box-shadow: inset 0 0 0 1px var(--err); }
.badge.queued { background: transparent; color: var(--muted);
  box-shadow: inset 0 0 0 1px var(--field); }
.badge.queued::before { background: transparent; border: 1.5px solid currentColor; }
.badge.running, .badge.uploading, .badge.done { background: var(--accent-soft);
  color: var(--accent-ink); }
.badge.uploading::before { border-radius: 1px; }
.badge.done::before { border-radius: 1px; transform: none; }
.badge.failed { background: var(--err-soft); color: var(--err-ink); }
.badge.failed::before { border-radius: 1px; transform: rotate(45deg); }
.empty { display: grid; gap: 14px; justify-items: start; margin-top: 20px; }
.note { margin-top: 16px; }
@media (forced-colors: active) {
  .job .segments span { forced-color-adjust: auto; background: Canvas;
    box-shadow: inset 0 0 0 1px CanvasText; }
  .job .segments span.on, .job .segments span.skip { background: CanvasText; }
  .job .segments span.now { box-shadow: inset 0 0 0 3px Highlight; }
  .job .segments span.bad { background: repeating-linear-gradient(135deg, CanvasText 0 3px,
    Canvas 3px 6px); }
}
@container (min-width: 640px) {
  .job:has(> a.btn) { grid-template-columns: minmax(0, 1fr) auto; column-gap: 24px;
    align-items: center; }
  .job-head, .job-meta, .job .segments, .job progress { grid-column: 1; }
  .job a.btn { grid-column: 2; grid-row: 1 / span 3; justify-self: end; }
}

/* --- People: admin cards --- */
.top h1 { margin-bottom: 4px; }
form.invite { display: flex; flex-wrap: wrap; gap: 8px; align-items: end; margin-top: 16px;
  padding: 16px; background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-m); }
form.invite label { flex-basis: 100%; }
form.invite input { flex: 1; min-width: 12rem; }
.flash { margin-top: 16px; padding: 10px 14px; border-radius: var(--r-m);
  background: var(--accent-soft); color: var(--accent-ink); font-weight: 600; }
.people { list-style: none; margin: 20px 0 0; padding: 0; display: grid; gap: 12px; }
.person { display: grid; gap: 12px; padding: 16px; background: var(--card);
  border: 1px solid var(--line); border-radius: var(--r-m); }
.person-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.person h2 { margin: 0; flex: 1 1 12rem; font-size: 1rem; line-height: 1.35;
  font-weight: 600; overflow-wrap: anywhere; }
.facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 16px;
  margin: 0; }
.facts dt { font-size: .75rem; color: var(--muted); letter-spacing: .04em;
  text-transform: uppercase; }
.facts dd { margin: 2px 0 0; overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
details > summary { display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  min-block-size: 40px; padding: 6px 14px; border: 1px solid var(--field);
  border-radius: var(--r-m); font-weight: 600; list-style: none; }
details > summary::-webkit-details-marker { display: none; }
details > summary::after { content: "+"; content: "+" / ""; font-weight: 400; }
details[open] > summary::after { content: "−"; content: "−" / ""; }
details > summary:hover { border-color: var(--ink); }
details.danger > summary { color: var(--err-ink); background: var(--err-soft);
  border-color: var(--err-ink); }
.manage-body { display: grid; gap: 12px; padding-block-start: 12px; }
.manage-body p { margin: 0; }
form.inline { display: inline-flex; flex-wrap: wrap; gap: 6px; }
form.inline { align-items: end; }
label.field { display: grid; gap: 2px; font-size: .75rem; color: var(--muted); }
form.inline input, form.inline select { padding: 6px 8px; border-radius: var(--r-s);
  font-size: .875rem; }
form.inline button { padding: 6px 12px; font-size: .875rem; border-radius: var(--r-s); }
@media (pointer: fine) { form.inline button { min-block-size: 36px; } }
form.inline button.danger { background: var(--err); color: var(--on-err); }
@media (pointer: coarse) { details > summary { min-block-size: var(--hit); }
  form.inline input, form.inline select { font-size: 1rem; } }
.flash:focus { outline: 0; }
@media (forced-colors: active) { .flash { border: 1px solid CanvasText; } }
@container (min-width: 720px) {
  .facts { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* --- Sign-in pages --- */
button.link { background: none; color: var(--accent); padding: 4px; text-decoration: underline; }
.ok { color: var(--accent); }

/* --- TIDAL and Spotify connection pages --- */
p.steps { color: var(--muted); font-size: 14px; line-height: 1.6; margin: 0; }
.success { color: var(--accent); font-weight: 600; font-size: 18px; margin: 0; }

/* --- Account --- */
.panel { margin-top: 16px; padding: 16px; background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-m); display: grid; gap: 12px; }
.panel h2 { margin: 0; font-size: 1rem; font-weight: 600; }
.rows { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.row-name { flex: 1 1 8rem; font-weight: 600; }
.panel fieldset { margin: 0; padding: 0; border: 0; min-width: 0; display: grid; gap: 4px; }
.panel legend { padding: 0 0 8px; font-size: .875rem; font-weight: 600; }
.choice { display: flex; align-items: flex-start; gap: 10px; min-block-size: var(--hit);
  padding: 8px 0; font-weight: 400; font-size: 1rem; cursor: pointer; }
.choice input { flex: none; inline-size: 20px; block-size: 20px; margin-block-start: 2px;
  padding: 0; min-block-size: 0; accent-color: var(--accent); }
.choice input:disabled + span { color: var(--muted); }
.choice:has(input:disabled) { cursor: not-allowed; }
.panel form { display: grid; gap: 12px; justify-items: start; }
.panel .note { margin: 0; font-size: .875rem; }
@container (min-width: 520px) {
  .row { display: grid; grid-template-columns: minmax(0, 1fr) auto 10rem; }
  .row .badge { justify-self: end; }
}

.notice { margin-top: 16px; padding: 10px 14px; border-radius: var(--r-m); background: var(--err-soft);
  color: var(--err-ink); border-inline-start: 4px solid var(--err-ink); font-weight: 600; }

.meter { display: grid; gap: 4px; }
.meter label { font-size: .875rem; font-weight: 600; }
.meter meter { inline-size: 100%; block-size: 12px; appearance: none;
  border: 1px solid var(--field); border-radius: 6px; background: var(--card); overflow: hidden; }
.meter meter::-webkit-meter-bar { background: var(--card); border: 0; block-size: 100%; }
.meter meter::-webkit-meter-optimum-value,
.meter meter::-webkit-meter-suboptimum-value,
.meter meter::-webkit-meter-even-less-good-value { background: var(--accent); }
.meter meter::-moz-meter-bar { background: var(--accent); }
.meter.full meter::-webkit-meter-optimum-value,
.meter.full meter::-webkit-meter-suboptimum-value,
.meter.full meter::-webkit-meter-even-less-good-value { background: var(--err); }
.meter.full meter::-moz-meter-bar { background: var(--err); }
@media (forced-colors: active) {
  .meter meter { forced-color-adjust: none; border-color: CanvasText; background: Canvas; }
  .meter meter::-webkit-meter-bar { background: Canvas; }
  .meter meter::-webkit-meter-optimum-value, .meter meter::-webkit-meter-suboptimum-value,
  .meter meter::-webkit-meter-even-less-good-value, .meter.full meter::-webkit-meter-optimum-value,
  .meter.full meter::-webkit-meter-suboptimum-value,
  .meter.full meter::-webkit-meter-even-less-good-value { background: Highlight; }
  .meter meter::-moz-meter-bar, .meter.full meter::-moz-meter-bar { background: Highlight; }
  .notice { border: 1px solid CanvasText; }
}
.meter span { font-size: .875rem; color: var(--muted); font-variant-numeric: tabular-nums; }
