/* ==========================================================================
   Resonance - admin stylesheet
   ADDED (reskin): replaces the flat amber-on-slate sheet.

   /login is the front door to both front ends, so the admin cannot look like a
   different product from the listening app. It borrows the whole Resonance
   language - glass panels, hairline borders, violet/cyan accent, pill tags -
   with one deliberate exception: the air. This is a dense data tool. Tables
   stay tight enough to scan a hundred rows, cards are padded for reading
   rather than for lounging, and nothing grows just because it can.

   The sheet is standalone - a server-rendered page cannot import from web/ -
   so the token block below is a straight copy of web/src/styles.css. Copy, do
   not paraphrase: the moment a value gets retyped from memory the two front
   ends start drifting and the shared identity is gone. Only the app-shell
   metrics (--sidebar-w, --player-h) are left out; there is no shell here.

   Every selector the 13 templates use still exists. New primitives are marked
   ADDED where they appear.
   ========================================================================== */

:root {
  /* Base ---------------------------------------------------------------- */
  --bg:        #07080c;
  --bg-raised: #0d0f16;
  --surface:   #12141c;
  --surface-2: #191c26;
  --line:      #262a36;

  --fg:        #eef0f6;
  --fg-dim:    #a3a9ba;
  --fg-faint:  #6b7285;

  /* Accent. Violet reads as "resonance" against the cool base and is far
     from the green/red the large services own. Cyan is the second stop,
     used only in gradients - never as a solid interactive colour. */
  --accent:      #a78bfa;
  --accent-fg:   #140b2b;
  --accent-2:    #38bdf8;
  --accent-soft: rgba(167, 139, 250, .14);

  --human:  #5fd39a;
  --model:  #7fa6e0;
  --import: #e8b04b;
  --danger: #f2716f;

  /* Glass --------------------------------------------------------------- */
  --glass-bg:      rgba(255, 255, 255, .045);
  --glass-bg-2:    rgba(255, 255, 255, .075);
  --glass-line:    rgba(255, 255, 255, .085);
  --glass-line-2:  rgba(255, 255, 255, .16);
  --glass-blur:    18px;
  --glass-shadow:  0 12px 40px rgba(0, 0, 0, .45);
  --glass-inset:   inset 0 1px 0 rgba(255, 255, 255, .06);

  /* Metrics ------------------------------------------------------------- */
  --radius:    12px;
  --radius-lg: 18px;
  --radius-xl: 24px;

  color-scheme: dark;

  /* Names carried over from the old sheet. ADDED as aliases rather than
     dropped: track_detail.html's waveform script reads --accent and --muted
     straight off the root to colour the canvas, and inline styles in the
     templates still reference --line. A custom property's computed value has
     var() already substituted, so the script gets a real colour back. */
  --card:    var(--surface);
  --muted:   var(--fg-dim);
  --warn:    var(--import);
  --machine: var(--model);
}

/* The app pins dark and offers its own toggle; the admin has no toggle, so it
   follows the app rather than the OS - two front ends that disagree about
   their own colour on the same screen was the problem being fixed. The
   override itself is the app's, verbatim, and works the moment anything sets
   the attribute. */
:root[data-theme="light"] {
  --bg:        #f4f4f8;
  --bg-raised: #ffffff;
  --surface:   #ffffff;
  --surface-2: #eeeef4;
  --line:      #e0e0e8;

  --fg:        #14141a;
  --fg-dim:    #545a6b;
  --fg-faint:  #858b9c;

  --accent:      #6d4aff;
  --accent-fg:   #ffffff;
  --accent-2:    #0ea5e9;
  --accent-soft: rgba(109, 74, 255, .12);

  --glass-bg:     rgba(255, 255, 255, .62);
  --glass-bg-2:   rgba(255, 255, 255, .82);
  --glass-line:   rgba(20, 20, 30, .08);
  --glass-line-2: rgba(20, 20, 30, .16);
  --glass-shadow: 0 12px 36px rgba(20, 20, 40, .12);
  --glass-inset:  inset 0 1px 0 rgba(255, 255, 255, .8);

  color-scheme: light;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--fg);
  font: 14px/1.5 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* The refraction source. Without it every blurred panel is just a lighter
   flat fill, so this is structural, not decoration. Fixed, so it stays put
   while a long table scrolls past it. */
body::before {
  content: "";
  position: fixed;
  inset: -20%;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(38% 42% at 12% 8%,  rgba(167, 139, 250, .22), transparent 70%),
    radial-gradient(34% 40% at 88% 12%, rgba(56, 189, 248, .16),  transparent 70%),
    radial-gradient(46% 46% at 72% 92%, rgba(236, 72, 153, .12),  transparent 72%);
  filter: blur(24px);
}
:root[data-theme="light"] body::before { opacity: .5; }

::selection { background: var(--accent-soft); }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--glass-line-2);
  border-radius: 6px;
  border: 2px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background-clip: border-box; }
* { scrollbar-width: thin; scrollbar-color: var(--glass-line-2) transparent; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }

/* ============================================================== chrome === */
nav {
  position: relative;
  z-index: 2;
  display: flex; align-items: center; gap: .15rem; flex-wrap: wrap;
  padding: .5rem 1.1rem;
  background: var(--glass-bg-2);
  border-bottom: 1px solid var(--glass-line);
  box-shadow: var(--glass-inset);
  backdrop-filter: blur(28px) saturate(165%);
  -webkit-backdrop-filter: blur(28px) saturate(165%);
}
/* The single specular line that makes a bar read as glass rather than as
   translucent plastic. */
nav::after {
  content: "";
  position: absolute; inset: 0 0 auto; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .28), transparent);
}
nav a {
  color: var(--fg-dim); text-decoration: none;
  padding: .34rem .6rem; border-radius: 9px;
  transition: background .14s, color .14s;
}
nav a:hover { color: var(--fg); background: var(--glass-bg); }
nav .brand {
  font-weight: 640; font-size: 1.02rem; letter-spacing: -.02em;
  color: var(--fg); margin-right: .55rem; padding-left: .2rem;
}
nav .brand:hover { background: none; }
nav .spacer { flex: 1; }
nav .who { color: var(--fg-faint); font-size: .82rem; padding-left: .4rem; }
nav .who em {
  font-style: normal; font-size: .71rem;
  background: var(--glass-bg); border: 1px solid var(--glass-line-2);
  border-radius: 999px; padding: .1rem .5rem; margin-left: .35rem;
  color: var(--fg-dim);
}
nav form { display: flex; }

/* The wordmark lockup: mark plus word, shared by the nav and the login card.
   ADDED - the mark itself is the same geometry the app draws. */
.brand { display: flex; align-items: center; gap: .55rem; }
.brand .mark { width: 24px; height: 24px; flex: none; display: block; }
.brand .word { line-height: 1; }

main {
  position: relative;
  z-index: 1;
  max-width: 1100px;
  margin: 0 auto;
  padding: 1.5rem 1.2rem 4rem;
}

/* ================================================================ type === */
/* Headings carry tags and the odd inline form, so they lay out as flex rows -
   that is what keeps "Audio features [Re-analyse]" and "name [role] [custom
   quota]" spaced consistently instead of relying on stray markup whitespace. */
h1 {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  font-size: 1.5rem; margin: 0 0 .3rem;
  letter-spacing: -.026em; font-weight: 660;
}
h2 {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  font-size: 1.02rem; margin: 1.5rem 0 .6rem;
  letter-spacing: -.012em; font-weight: 620;
}
p.hint { color: var(--fg-dim); margin: .2rem 0 1.1rem; }

/* Gradient display type. Reserved for the wordmark, as in the app. */
.grad {
  background: linear-gradient(96deg, var(--fg) 10%, var(--accent) 55%, var(--accent-2) 95%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 2px; }

code {
  font-size: .85em;
  background: rgba(0, 0, 0, .3);
  border: 1px solid var(--glass-line);
  border-radius: 6px; padding: .05rem .35rem;
}
:root[data-theme="light"] code { background: rgba(0, 0, 0, .045); }

/* Search snippets arrive from OpenSearch wrapped in <mark>; the browser
   default is a yellow block that is unreadable on this background. */
mark {
  background: var(--accent); color: var(--accent-fg);
  border-radius: 4px; padding: 0 .18rem;
}

/* =============================================================== panels == */
.card {
  position: relative;
  background: var(--glass-bg);
  border: 1px solid var(--glass-line);
  border-radius: var(--radius-lg);
  box-shadow: var(--glass-shadow), var(--glass-inset);
  backdrop-filter: blur(var(--glass-blur)) saturate(150%);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(150%);
  padding: .95rem 1.05rem;
  margin-bottom: 1.1rem;
}

/* Where backdrop-filter is unsupported the blur silently does nothing and a
   translucent panel over a busy wash becomes unreadable, so opt into a solid. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .card, nav { background: var(--surface); }
}

.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; }
@media (max-width: 760px) { .grid2 { grid-template-columns: 1fr; } }

/* =============================================================== tables == */
/* Tight on purpose. The row hover is hung off td rather than tr because most
   of these tables put their <th> row directly in the table with no <thead>,
   and a header that lights up on hover reads as clickable. */
table { width: 100%; border-collapse: collapse; font-size: .875rem; }
th, td {
  text-align: left; padding: .42rem .55rem;
  border-bottom: 1px solid var(--glass-line);
  vertical-align: top;
}
th {
  color: var(--fg-faint); font-weight: 650; font-size: .71rem;
  text-transform: uppercase; letter-spacing: .07em;
  border-bottom-color: var(--glass-line-2);
  white-space: nowrap;
}
tr:last-child td { border-bottom: none; }
tr:hover td { background: var(--glass-bg); }
td strong { font-weight: 600; }
td form { display: inline-flex; gap: .35rem; }

/* ================================================================ forms == */
form.inline, .inline {
  display: flex; gap: .6rem; flex-wrap: wrap; align-items: flex-end;
}
label {
  display: flex; flex-direction: column; gap: .22rem;
  font-size: .75rem; color: var(--fg-faint);
}
label.check {
  flex-direction: row; align-items: center; gap: .38rem;
  font-size: .82rem; color: var(--fg-dim);
  padding-bottom: .45rem;
}

input, select, textarea {
  background: rgba(0, 0, 0, .22);
  color: var(--fg);
  border: 1px solid var(--glass-line);
  border-radius: 10px;
  padding: .4rem .6rem;
  font: inherit;
  min-width: 8rem;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: border-color .14s, background .14s, box-shadow .14s;
}
:root[data-theme="light"] input,
:root[data-theme="light"] select,
:root[data-theme="light"] textarea { background: rgba(255, 255, 255, .7); }
input::placeholder { color: var(--fg-faint); }
input:hover, select:hover { border-color: var(--glass-line-2); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
input[type=checkbox] {
  min-width: auto; width: 1rem; height: 1rem;
  align-self: center; accent-color: var(--accent);
}
input[type=file] { padding: .28rem .4rem; min-width: 14rem; }
input[type=file]::file-selector-button {
  font: inherit; font-size: .8rem; cursor: pointer;
  margin-right: .6rem; padding: .25rem .65rem;
  border: 1px solid var(--glass-line-2); border-radius: 8px;
  background: var(--glass-bg); color: var(--fg-dim);
}
input[type=file]::file-selector-button:hover { color: var(--fg); background: var(--glass-bg-2); }

button {
  background: linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent-2) 60%, var(--accent)));
  color: var(--accent-fg);
  /* Transparent rather than none, so a primary and a ghost sitting next to
     each other in a table cell are exactly the same height. */
  border: 1px solid transparent;
  border-radius: 10px;
  padding: .42rem .85rem;
  font: inherit; font-weight: 580;
  cursor: pointer;
  box-shadow: 0 4px 14px rgba(167, 139, 250, .28);
  transition: filter .12s, transform .08s, box-shadow .12s;
}
button:hover { filter: brightness(1.08); box-shadow: 0 6px 20px rgba(167, 139, 250, .38); }
button:active { transform: translateY(1px); }
button:disabled { opacity: .42; cursor: default; box-shadow: none; }

/* The quiet second action - log out, roll back, send back to draft. Was an
   underlined text link; a ghost keeps it clearly secondary without pretending
   to be a link on a page where links are violet. */
button.link {
  background: var(--glass-bg); color: var(--fg-dim);
  border-color: var(--glass-line);
  font-weight: 500;
  text-decoration: none;
  box-shadow: none;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
button.link:hover {
  color: var(--fg); background: var(--glass-bg-2);
  border-color: var(--glass-line-2);
  filter: none; box-shadow: none;
}
/* A button that sits inside a heading or a table row is that row's action, not
   the page's - it inherits the surrounding font otherwise and starts shouting. */
td button, h1 button, h2 button { padding: .28rem .62rem; font-size: .8rem; font-weight: 560; }
nav button.link { padding: .3rem .65rem; font-size: .82rem; }

audio { max-width: 100%; border-radius: 10px; }

/* ================================================================= tags == */
.tag {
  display: inline-block;
  font-size: .71rem; line-height: 1.5;
  padding: .12rem .5rem;
  border-radius: 999px;
  border: 1px solid var(--glass-line-2);
  color: var(--fg-dim);
  white-space: nowrap;
  background: var(--glass-bg);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.tag.human  { border-color: color-mix(in srgb, var(--human) 55%, transparent);  color: var(--human); }
.tag.model  { border-color: color-mix(in srgb, var(--model) 55%, transparent);  color: var(--model); }
/* ADDED: provenance rows render `.tag {{ producer_kind }}`, and import is one
   of the kinds the pipeline writes. */
.tag.import { border-color: color-mix(in srgb, var(--import) 55%, transparent); color: var(--import); }

/* ============================================================= messages == */
.empty { color: var(--fg-faint); font-style: italic; padding: .5rem 0; }

.err, .ok {
  padding: .55rem .8rem;
  border-radius: var(--radius);
  margin: 0 0 1rem;
  color: var(--fg);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.err {
  background: color-mix(in srgb, var(--danger) 16%, var(--glass-bg));
  border: 1px solid color-mix(in srgb, var(--danger) 45%, transparent);
}
.ok {
  background: color-mix(in srgb, var(--human) 15%, var(--glass-bg));
  border: 1px solid color-mix(in srgb, var(--human) 42%, transparent);
}

/* ================================================================ login == */
/* The front door to both front ends, so it is the one place here that is
   allowed to be a little generous with space. */
.login {
  max-width: 23rem;
  margin: min(14vh, 7rem) auto;
  padding: 1.6rem 1.5rem 1.5rem;
  background: var(--glass-bg-2);
  border-color: var(--glass-line-2);
  backdrop-filter: blur(28px) saturate(165%);
  -webkit-backdrop-filter: blur(28px) saturate(165%);
}
.login h1 {
  gap: .65rem;
  font-size: 1.7rem;
  margin-bottom: .45rem;
}
.login .mark { width: 34px; height: 34px; }
.login p.hint { margin-bottom: 1.3rem; }
.login label { margin-bottom: .75rem; }
.login input { width: 100%; min-width: 0; }
.login button { width: 100%; margin-top: .35rem; padding: .55rem 1rem; }

/* ========================================================== responsive === */
@media (max-width: 640px) {
  nav { gap: .1rem; padding: .5rem .7rem; }
  main { padding: 1.1rem .8rem 3rem; }
  .login { margin: 2.5rem auto; }
  h1 { font-size: 1.3rem; }
}

/* The washes breathe, slowly enough that it never reads as an animation - it
   just stops the background looking like a printed sheet. */
@media (prefers-reduced-motion: no-preference) {
  body::before { animation: aurora 34s ease-in-out infinite alternate; }
}
@keyframes aurora {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(0, -3%, 0) scale(1.07); }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
  body::before { animation: none !important; }
}
