/* The catalogue console.
 *
 * Same tokens as the venue app, deliberately different density. This is an instrument panel for
 * one operator looking at fifty thousand rows, not a room's dashboard: tables win over cards,
 * numbers win over pictures, and nothing animates unless it is reporting progress.
 *
 * It is a separate page for a reason. It revokes tracks, deletes masters and decides what the
 * whole estate plays - it must never be one wrong click away from a venue's screen. */

:root { --admin-rail: 210px; }

/* The same sky as the venue app, to the same stops. This file is now the standard for both
   internal tools: the administration copies it in and uses these class names rather than
   resembling them, so the rail, the cards, the tables and the buttons are one file, not two that
   look alike. */
body.admin {
  margin: 0;
  min-height: 100vh;
  font-family: var(--font-ui);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  background:
    linear-gradient(180deg,
      rgba(140,190,238,.92) 0%,
      rgba(168,206,242,.62) 16%,
      rgba(200,225,246,.30) 32%,
      rgba(226,238,250,.10) 46%,
      rgba(255,255,255,0) 58%),
    #eef2f7;
  background-attachment: fixed;
}
[data-theme="dark"] body.admin {
  background:
    linear-gradient(180deg,
      rgba(126,146,176,.30) 0%,
      rgba(108,128,158,.18) 18%,
      rgba(86,104,132,.09) 34%,
      rgba(60,74,96,.03) 48%,
      rgba(0,0,0,0) 60%),
    #10151c;
  background-attachment: fixed;
}

.a-shell { display: grid; grid-template-columns: var(--admin-rail) minmax(0, 1fr) 330px; min-height: 100vh; }
@media (max-width: 1400px) { .a-shell { grid-template-columns: var(--admin-rail) minmax(0, 1fr); } .a-insp { display: none; } }

/* ---------------------------------------------------------------- rail */
.a-rail { padding: 18px 12px; position: sticky; top: 0; height: 100vh; box-sizing: border-box;
  backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur);
  background: var(--glass-bg); box-shadow: var(--glass-edge), var(--glass-shadow); }
.a-brand { display: flex; align-items: baseline; gap: 8px; padding: 0 8px 18px; }
.a-brand b { font-family: var(--font-display); font-size: 21px; letter-spacing: .02em;
  /* asked for twice: Syne is variable and Safari honours the axis more reliably */
  font-weight: 700; font-variation-settings: 'wght' 700; }
.a-brand span { font-size: 11px; letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--muted); }
.a-nav { display: flex; flex-direction: column; gap: 2px; }
.a-nav button {
  all: unset; cursor: pointer; padding: 8px 10px; border-radius: var(--r-2);
  font-size: 14.3px; color: var(--muted); display: flex; justify-content: space-between; gap: 8px;
}
.a-nav button:hover { background: var(--surface-hover); color: var(--ink); }
.a-nav button[aria-current="true"] { background: var(--surface); color: var(--ink); font-weight: 600; }
.a-nav .n { font-size: 12.1px; color: var(--muted); }
.a-rail-foot { position: absolute; bottom: 16px; left: 12px; right: 12px; font-size: 11.6px; color: var(--muted); line-height: 1.5; }

/* ---------------------------------------------------------------- main */
.a-main { padding: 20px 24px 120px; min-width: 0; }
.a-head { display: flex; align-items: center; gap: 14px; margin-bottom: 16px; flex-wrap: wrap; }
.a-head h1 { font-family: var(--font-display); font-size: 22px; margin: 0; font-weight: 600; }
.a-head .sp { flex: 1; }

.pill { font-size: 12.1px; padding: 3px 9px; border-radius: var(--r-pill); border: 1px solid var(--surface-brd); color: var(--muted); }
.pill.on { border-color: var(--accent); color: var(--accent-deep); }
.pill.bad { border-color: #C05B4A; color: #C05B4A; }

.a-card { border: var(--glass-brd); border-radius: var(--r-2); padding: 16px 18px; margin-bottom: 14px;
  backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur);
  background: var(--glass-bg); box-shadow: var(--glass-edge), var(--glass-shadow); }
.a-card h2 { font-size: 13.2px; letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--muted); margin: 0 0 10px; font-weight: 600; }
.a-grid { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }

.stat { display: flex; flex-direction: column; gap: 2px; }
.stat b { font-family: var(--font-display); font-size: 28.6px; font-weight: 600; line-height: 1; }
.stat span { font-size: 12.1px; color: var(--muted); letter-spacing: .04em; }

/* ---------------------------------------------------------------- controls */
button.btn, .btn {
  all: unset; cursor: pointer; box-sizing: border-box;
  padding: 8px 15px; border-radius: var(--r-1); font-size: 13px; font-weight: 600;
  border: 1px solid var(--surface-brd); background: var(--surface); color: var(--ink);
  transition: var(--t-fast);
}
button.btn:hover { background: var(--surface-hover); }
button.btn[disabled] { opacity: .45; cursor: default; }
button.btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }
button.btn.primary:hover { filter: brightness(1.06); background: var(--accent); }
button.btn.danger { border-color: rgba(192,57,47,.45); color: #c0392f; background: rgba(192,57,47,.10); }
button.btn.danger:hover { background: rgba(192,57,47,.18); }
[data-theme="dark"] button.btn.danger { color: #e8736a; border-color: rgba(232,115,106,.5);
  background: rgba(232,115,106,.12); }
.row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
input[type=text], input[type=number], input[type=month], select {
  font: inherit; font-size: 13px; color: var(--ink); padding: 8px 12px;
  border: 1px solid var(--surface-brd); border-radius: var(--r-1); background: var(--surface);
  font-family: var(--font-ui); outline: none; transition: var(--t-fast);
}
input[type=text]:focus, input[type=number]:focus, input[type=month]:focus, select:focus {
  border-color: var(--accent); box-shadow: 0 0 0 3px rgba(62,133,211,.14);
}
input[type=text] { min-width: 220px; }
label.f { display: flex; flex-direction: column; gap: 4px; font-size: 12.1px; color: var(--muted); }

/* ---------------------------------------------------------------- progress */
.bar { height: 6px; border-radius: 3px; background: var(--track); overflow: hidden; }
.bar i { display: block; height: 100%; background: var(--accent); transition: width .4s var(--ease); }

/* ---------------------------------------------------------------- tables */
table.a-t { width: 100%; border-collapse: collapse; font-size: 13.8px; }
table.a-t th {
  text-align: left; font-size: 11px; letter-spacing: var(--ls-label); text-transform: uppercase;
  color: var(--muted); font-weight: 600; padding: 6px 8px; border-bottom: 1px solid var(--hairline);
  position: sticky; top: 0; background: var(--bg-bot);
  backdrop-filter: blur(8px);
}
table.a-t td { padding: 6px 8px; border-bottom: 1px solid var(--hairline); vertical-align: top; }
table.a-t tbody tr:hover { background: var(--surface-hover); cursor: default; }
table.a-t tbody tr.sel { background: var(--surface); }
table.a-t td.num, table.a-t th.num { text-align: right; font-variant-numeric: tabular-nums; }
.scroll { max-height: 62vh; overflow: auto; }
.muted { color: var(--muted); }
.mono { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12.7px; }
.wrap-any { overflow-wrap: anywhere; }

/* state chips - the colour says how far a track got, and whether anyone must act */
.st { font-size: 11.6px; padding: 2px 7px; border-radius: var(--r-pill); border: 1px solid var(--surface-brd); color: var(--muted); white-space: nowrap; }
.st-ready { border-color: #3E8E6E; color: #3E8E6E; }
.st-analysed, .st-fetched { border-color: var(--accent); color: var(--accent-deep); }
.st-missing { border-color: #B08A3A; color: #B08A3A; }
.st-failed, .st-revoked { border-color: #C05B4A; color: #C05B4A; }

/* ---------------------------------------------------------------- inspector */
.split { display: grid; grid-template-columns: 1.15fr .85fr; gap: 14px; align-items: start; }
@media (max-width: 1100px) { .split { grid-template-columns: 1fr; } }
.kv { display: grid; grid-template-columns: 130px 1fr; gap: 3px 10px; font-size: 13.2px; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; }
audio { width: 100%; margin: 8px 0; }
.note { font-size: 12.1px; color: var(--muted); line-height: 1.5; }
.warn { border-left: 2px solid #B08A3A; padding-left: 10px; }

/* ---------------------------------------------------------------- workbench */
.rail-h { font-size: 11px; letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--muted); padding: 12px 10px 6px; }
.work-grid { display: block; }
/* without this a wide review table stretches its grid track and pushes the stage rail off-screen */
.work-grid > #stage-body { min-width: 0; }
@media (max-width: 1150px) { .work-grid { grid-template-columns: 1fr; } }

/* audition card - the one screen that has to be fast under the hand */
.audition { text-align: center; padding: 8px 0 4px; }
.audition h3 { font-family: var(--font-display); font-size: 24.2px; margin: 0 0 2px; font-weight: 600; }
.audition .by { color: var(--muted); font-size: 14.3px; margin-bottom: 10px; }
.audition .meta { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; font-size: 12.7px; color: var(--muted); margin-bottom: 10px; }
.audition .meta b { color: var(--ink); font-weight: 600; }
.keys { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 12px; }
.keys .btn { min-width: 108px; text-align: center; }
kbd {
  font: inherit; font-size: 11.6px; border: 1px solid var(--surface-brd); border-radius: 3px;
  padding: 0 4px; margin-left: 6px; color: var(--muted);
}

/* the review table: colour says who said so */

td[contenteditable="true"]:focus { outline: 2px solid var(--accent); outline-offset: -2px; background: var(--surface); }

/* ------------------------------------------------------- the fixed inspector */
.a-insp {
  border-left: 1px solid var(--hairline); padding: 18px 16px 120px;
  position: sticky; top: 0; height: 100vh; overflow: auto; box-sizing: border-box;
}
.a-insp h2 { font-size: 11px; letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--muted); margin: 16px 0 8px; font-weight: 600; }
.a-insp h2:first-child { margin-top: 0; }
.insp-empty { padding-top: 40px; }
.insp-cover {
  width: 100%; aspect-ratio: 1; border-radius: 7px; overflow: hidden; background: var(--surface);
  display: grid; place-items: center; margin-bottom: 8px;
}
.insp-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.insp-cover .none { font-size: 12.1px; color: var(--muted); text-align: center; padding: 0 20px; }
.insp-title { font-family: var(--font-display); font-size: 17.6px; font-weight: 600; line-height: 1.2; }
.insp-artist { color: var(--muted); font-size: 13.8px; margin-bottom: 6px; }
.insp-res { font-size: 12.1px; color: var(--muted); }
.insp-res b { color: var(--ink); font-weight: 600; }
.insp-res.small { color: #B08A3A; }
.fields { display: grid; grid-template-columns: 96px 1fr; gap: 3px 8px; font-size: 12.7px; }
.fields dt { color: var(--muted); overflow-wrap: anywhere; }
.fields dd { margin: 0; overflow-wrap: anywhere; }
.tag { font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; padding: 1px 5px; border-radius: 3px; }
.tag-provider { background: rgba(62,133,211,.16); color: var(--accent-deep); }
.tag-measured { background: rgba(53,196,181,.18); color: #2C8377; }
.tag-ours { background: rgba(243,178,76,.22); color: #9A6B14; }

/* ------------------------------------------------------------------- the dock
 *
 * The venue app's transport, at the venue app's proportions. One product, one player: a person who
 * has used the room screen should not have to learn a second set of controls to audition a track. */
.dock {
  position: fixed; left: 50%; transform: translateX(-50%); bottom: 14px; z-index: 50;
  box-sizing: border-box; width: clamp(620px, 64vw, 940px);
  display: flex; align-items: center; gap: 18px; padding: 10px 16px;
  border-radius: var(--r-1); border: 1px solid var(--surface-brd);
  background: var(--glass-bg); backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow);
}

.dock-now { display: flex; align-items: center; gap: 12px; width: 210px; flex: none; min-width: 0; }
.dock-art {
  width: 48px; height: 48px; border-radius: 4.5px; flex: none; object-fit: cover;
  background: var(--surface);
}
.dock-meta { min-width: 0; }
.dock-title { font-size: 14px; font-weight: 600; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dock-artist { font-size: 11.5px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.dock-ctl { flex: 1; display: flex; align-items: center; gap: 12px; min-width: 0; }

.pb-btn, .pb-skip, .pb-prev {
  all: unset; position: relative; flex: none; cursor: pointer; color: var(--muted);
  display: grid; place-items: center; border-radius: 50%;
  transition: transform .12s var(--ease), color .12s var(--ease);
}
.pb-btn:hover, .pb-skip:hover, .pb-prev:hover { color: var(--accent-deep); }
[data-theme="dark"] .pb-btn:hover, [data-theme="dark"] .pb-skip:hover, [data-theme="dark"] .pb-prev:hover { color: var(--accent-glow); }
.pb-btn:active, .pb-skip:active, .pb-prev:active { transform: scale(.88); }
.pb-btn { width: 52px; height: 52px; color: var(--accent-deep); }
[data-theme="dark"] .pb-btn { color: var(--accent-glow); }
.pb-btn svg { width: 36px; height: 36px; display: block; }
.pb-skip, .pb-prev { width: 36px; height: 36px; }
.pb-skip svg, .pb-prev svg { width: 20px; height: 20px; display: block; transition: transform .15s ease-out; }
.pb-skip:hover svg { transform: translateX(2px); }
.pb-prev:hover svg { transform: translateX(-2px); }

.pb-t { font-size: 13px; color: var(--muted); flex: none; font-variant-numeric: tabular-nums; }
.progress { flex: 1; height: 5px; border-radius: 3px; background: var(--track); cursor: pointer; position: relative; min-width: 60px; }
.pfill { position: absolute; inset: 0 auto 0 0; width: 0; background: var(--accent); border-radius: 3px; }
.pfill .phead {
  position: absolute; right: -5px; top: 50%; transform: translateY(-50%);
  width: 10px; height: 10px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 1px 4px rgba(18,40,70,.35);
}

.dock-vol { display: flex; align-items: center; gap: 9px; flex: none; }
.vol-btn {
  all: unset; width: 32px; height: 32px; flex: none; cursor: pointer; color: var(--muted);
  display: grid; place-items: center; border-radius: 50%;
}
.vol-btn:hover { color: var(--ink); background: var(--surface-hover); }
.vol-btn svg { width: 21px; height: 21px; display: block; }
.vol { width: 84px; height: 5px; border-radius: 3px; background: var(--track); cursor: pointer; position: relative; }
.vol-fill { position: absolute; inset: 0 auto 0 0; background: var(--muted); border-radius: 3px; }

.dock-of { font-size: 11px; color: var(--muted); flex: none; min-width: 44px; text-align: right; }
@media (max-width: 1150px) { .dock-of { display: none; } .dock { width: 92vw; } }

/* ------------------------------------------------- the rail's own small controls */
.rail-add {
  all: unset; cursor: pointer; float: right; width: 18px; height: 18px; margin-top: -2px;
  border-radius: 4px; text-align: center; line-height: 17px; font-size: 15px; color: var(--muted);
}
.rail-add:hover { background: var(--surface-hover); color: var(--ink); }

.a-nav button .more {
  opacity: 0; margin-left: 4px; padding: 0 4px; border-radius: 4px; color: var(--muted);
  letter-spacing: 1px;
}
.a-nav button:hover .more { opacity: 1; }
.a-nav button .more:hover { background: var(--surface-hover); color: var(--ink); }

.rowmenu {
  position: fixed; z-index: 80; padding: 5px; margin: 0; min-width: 168px;
  display: flex; flex-direction: column; background: var(--bg-bot);
  box-shadow: 0 10px 30px rgba(10,25,45,.18);
}
.rowmenu button {
  all: unset; cursor: pointer; padding: 7px 10px; border-radius: var(--r-2); font-size: 12.5px;
}
.rowmenu button:hover { background: var(--surface-hover); }
.rowmenu button.danger { color: #C05B4A; }

/* ------------------------------------------------------------ column widths
 *
 * A table set to full width and left to its own devices spreads two short columns across half the
 * screen and puts a header a hand's width from the number it labels. Fixed widths for everything
 * that is a number or a symbol; the title and the artist share what is left. */
#rows { table-layout: fixed; }

#tracks { table-layout: fixed; }
#tracks th:nth-child(1), #tracks td:nth-child(1) { width: 46px; }
#tracks th:nth-child(2), #tracks td:nth-child(2) { width: 34%; }
#tracks th:nth-child(3), #tracks td:nth-child(3) { width: 26%; }
#tracks th:nth-child(4), #tracks td:nth-child(4) { width: 74px; }
#tracks th:nth-child(5), #tracks td:nth-child(5) { width: 66px; padding-right: 18px; }
#tracks th:nth-child(6), #tracks td:nth-child(6) { width: 140px; }
#tracks th:last-child, #tracks td:last-child { width: 108px; overflow: visible; }

/* every cell that holds text keeps to one line and ends in an ellipsis rather than pushing its
   neighbours out of shape */
#tracks td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------------------------------------------------- the delivery list, restored
 *
 * These rules were lost when the dock was rebuilt: the patch replaced a region of this file and
 * took the table's own styling with it. Kept together at the end now, where a later edit to the
 * dock cannot reach them. */

/* The counts, as one line rather than a wall of tiles. They are filters, so they have to be
   pressable, but they are also the least important thing on the screen and were taking the most
   room. Numbers in ink, labels in grey, hairlines between. */
.chips {
  display: flex; flex-wrap: wrap; align-items: center; margin-bottom: 12px;
  border: 1px solid var(--hairline); border-radius: var(--r-1);
  background: var(--glass-bg); padding: 2px 4px;
}
.chips .chip {
  all: unset; cursor: pointer; padding: 6px 12px; display: flex; align-items: baseline; gap: 6px;
  border-radius: var(--r-2); position: relative; white-space: nowrap;
}
.chips .chip + .chip::before {
  content: ''; position: absolute; left: 0; top: 6px; bottom: 6px; width: 1px;
  background: var(--hairline);
}
.chips .chip:hover { background: var(--surface-hover); }
.chips .chip.on { background: var(--surface); box-shadow: inset 0 -2px 0 var(--accent); }
.chips .chip b { font-family: var(--font-display); font-size: 15px; font-weight: 600; }
.chips .chip span { font-size: 11.5px; color: var(--muted); }
.chips .chip.on span { color: var(--ink); }

/* one narrow column per step: a tick is readable at a glance, six symbols in one cell are not */
/* the label has to live inside its own 28 pixels, so it is short and it is small - a clipped
   header is worse than a terse one */
/* Prefixed with the table's id on purpose. `table.a-t th` is two elements and a class, which beats
   a bare `th.tickcol` - every rule below was being silently ignored, which is why the headers kept
   coming out clipped however small the font was set. */
#rows th.tickcol {
  text-align: center; width: 28px; padding: 6px 1px;
  text-transform: none; letter-spacing: 0; font-size: 9.5px;
}
#rows td.tickcol { text-align: center; width: 28px; padding: 6px 2px; color: var(--track); font-size: 16px; }
#rows td.tickcol.yes { color: #3E8E6E; }
#rows td.tickcol.no { color: #C05B4A; }
#rows td.tickcol.part { color: #B08A3A; }

/* The buttons ride along the right while the ticks scroll under them, on a solid fill - a gradient
   let the columns show through and read as overlap rather than as a pinned column. */
#rows th.acts, #rows td.acts, #tracks th.acts, #tracks td.acts {
  white-space: nowrap; text-align: right; position: sticky; right: 0;
  background: var(--bg-bot); box-shadow: -10px 0 10px -8px rgba(10,25,45,.22);
}
#rows tbody tr:hover td.acts, #tracks tbody tr:hover td.acts { background: var(--bg-bot); }
#rows td.acts .btn, #tracks td.acts .btn { margin-left: 3px; padding: 4px 8px; font-size: 11.5px; }

#rows td.titlecell b { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#rows td.titlecell .muted { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11.5px; }

/* the play button's three states */
.btn.play-one { position: relative; width: 34px; height: 26px; padding: 0; text-align: center; }
.btn.play-one .glyph { font-size: 11px; line-height: 1; }
.btn.play-one .eq { display: none; align-items: flex-end; justify-content: center; gap: 2px; height: 12px; }
.btn.play-one .eq i { display: block; width: 2.5px; background: var(--accent); height: 4px; border-radius: 1px; }
.btn.play-one.sounding .eq { display: flex; }
.btn.play-one.sounding .glyph { display: none; }
.btn.play-one.sounding:hover .eq { display: none; }
.btn.play-one.sounding:hover .glyph { display: inline; }
.btn.play-one.current { border-color: var(--accent); }
.btn.play-one.sounding .eq i:nth-child(1) { animation: eqbar .62s ease-in-out infinite alternate; }
.btn.play-one.sounding .eq i:nth-child(2) { animation: eqbar .44s ease-in-out infinite alternate .12s; }
.btn.play-one.sounding .eq i:nth-child(3) { animation: eqbar .78s ease-in-out infinite alternate .06s; }
@keyframes eqbar { from { height: 3px; } to { height: 12px; } }

/* the loading card, when it is shown at all */
#load-card h2 { margin-top: 0; }

/* widths again, after the restored rules, so nothing above overrides them */
#rows { table-layout: fixed; }

/* A track already in the catalogue reads green at a glance, which is what a person scanning two
   hundred rows is doing. It stays a button, because pressing it takes the track back out. */
button.btn.done {
  background: rgba(62,142,110,.14); border-color: rgba(62,142,110,.55); color: #2F7458;
}
button.btn.done:hover { background: rgba(62,142,110,.24); }
[data-theme="dark"] button.btn.done { color: #7FD3AE; border-color: rgba(127,211,174,.45); background: rgba(127,211,174,.14); }

/* A suspicion, said on the row rather than kept for a report nobody opens. Amber is "look at this",
   red is "this is the same music twice". */
.flag {
  display: inline-block; margin: 3px 4px 0 0; padding: 1px 6px; border-radius: 3px;
  font-size: 10px; letter-spacing: .02em;
  background: rgba(176,138,58,.16); color: #8A6A22;
}
.flag.bad { background: rgba(192,91,74,.16); color: #A8432F; }
[data-theme="dark"] .flag { background: rgba(243,178,76,.18); color: #E7C07A; }
[data-theme="dark"] .flag.bad { background: rgba(224,120,100,.2); color: #E9A192; }

/* The row number. Narrow, quiet, and monospaced so a column of them lines up - it exists to be
   read out loud ("look at 147"), not to be looked at. */
#rows th.numcol, #rows td.numcol {
  width: 34px; text-align: right; padding-right: 6px;
  font: 400 11px/1 var(--mono, ui-monospace, monospace);
  color: var(--muted, #7b8794); vertical-align: middle;
}

/* Widths are positional under table-layout: fixed, so a new first column shifts every one of them.
   That is what squeezed the title to ninety pixels and pushed the length under the first tick:
   the rules still described the old column order. Now they name the classes instead, so the next
   column somebody adds cannot silently move them again. */
#rows th.numcol,   #rows td.numcol    { width: 32px; text-align: right; padding-right: 4px; }
#rows th.playcol,  #rows td.playcell  { width: 44px; }
#rows th.trackcol, #rows td.titlecell { width: auto; }
#rows th.lencol,   #rows td.lencell   { width: 62px; padding-right: 12px; }
#rows th.acts,     #rows td.acts      { width: 250px; }
#rows td.titlecell .flag { display: inline-block; white-space: nowrap; margin-top: 3px; }

/* A keyboard hint that looks like a key. The shortcuts existed from the first day and nothing on
   screen said so, which is the same as not having them. */
.key {
  display: inline-block; min-width: 15px; padding: 1px 4px; margin: 0 1px;
  border: 1px solid var(--line, #d7dde5); border-radius: 3px;
  background: var(--bg-bot, #fff); font: 600 10px/1.4 var(--mono, ui-monospace, monospace);
  text-align: center; color: var(--muted, #7b8794); vertical-align: baseline;
}
.rowmenu button .key { float: right; margin-left: 14px; }

/* In the catalogue, but its files never reached storage. The only state the two removed ticks were
   genuinely needed for, so it has to be loud where they were quiet: the button says the fault and
   pressing it retries the send. */
.btn.warnstate {
  background: #FBF1DA; border-color: #D9BC7A; color: #7A5B1E; font-weight: 600;
}
.btn.warnstate:hover { background: #F6E7C4; }

/* A removed track stays where it was. Hiding it would answer "did I already deal with this one?"
   with silence, and the decision has to be as visible - and as reversible - as making it was. */
/* Taken out, not broken. Grey rather than red: red is for something that went wrong, and a track
   somebody decided against is a decision, not a fault. */
#rows tr.out td { background: #F1F2F4; color: #8A9099; }
#rows tr.out td.titlecell b { color: #7A828C; font-weight: 500; }
#rows tr.out td.tickcol.yes { color: #A9B0B8; }
#rows tr.out .play-one, #rows tr.out td.numcol { opacity: .55; }
#rows tr.out:hover td { background: #E9EBEE; }
#rows tr.out.sel td { background: #E4E7EB; }

/* Removal and erasure are row buttons again, not a menu. A menu hides how destructive a thing is
   behind a shrug of three dots; a button that greys out when the track is in the catalogue says
   the rule itself - take it out of the catalogue first. */
#rows td.acts .btn.iconbtn { padding: 4px 7px; font-size: 12px; line-height: 1.1; min-width: 26px; }
#rows td.acts .btn.iconbtn.danger { font-size: 11px; letter-spacing: .2px; }
#rows td.acts .btn.iconbtn.danger { color: #B05548; border-color: #E3C6C1; }
#rows td.acts .btn.iconbtn.danger:hover:not(:disabled) { background: #FBEDEA; border-color: #C88A7E; }
#rows td.acts .btn.iconbtn:disabled { opacity: .32; }

/* Two boxes, two jobs. One pile that did everything at once is how the wrong export became the
   register with nothing on screen to say so. */
.two-drops { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 12px; }
.droptitle { font: 600 12px/1.4 var(--ui, inherit); letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted, #7b8794); margin: 0 0 6px; }
.dropzone { border: 1px dashed var(--surface-brd, #d7dde5); border-radius: var(--r-1, 8px);
  padding: 26px 16px; text-align: center; color: var(--muted, #7b8794); font-size: 13.5px;
  transition: border-color .12s, background .12s; }
.dropzone.over { border-color: var(--accent, #2F6BE0); background: rgba(47,107,224,.05); }

/* A metadata file, shown with enough of itself to be recognised before it is read. */
.mf { border: 1px solid var(--surface-brd, #d7dde5); border-radius: var(--r-1, 8px);
  padding: 10px 12px; margin-top: 8px; display: grid;
  grid-template-columns: 1fr auto; grid-template-areas: "name acts" "note acts" "samp acts";
  align-items: center; gap: 2px 12px; }
.mf-name { grid-area: name; font-weight: 600; font-size: 13.5px; }
.mf .note { grid-area: note; margin: 0; }
.mf .mf-sample { grid-area: samp; opacity: .75; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mf-acts { grid-area: acts; display: flex; gap: 6px; }
.mf.on { border-color: #9CC7AE; background: #F4FAF6; }
.mf.bad { border-color: #E3C6C1; background: #FCF4F2; }
@media (max-width: 900px) { .two-drops { grid-template-columns: 1fr; } }

/* The register describes different audio. Every counter already said so quietly; quiet was the bug. */
.alarm { border: 1px solid #D9A79A; background: #FCF0EC; border-radius: var(--r-1, 8px);
  padding: 12px 14px; margin: 10px 0; }
.alarm b { color: #A24A38; font-size: 14px; }
.alarm .note { margin: 4px 0 10px; }

/* The gate between the antechamber and the processor. */
.gate { border-radius: var(--r-1, 8px); padding: 12px 14px; margin-top: 12px; }
.gate.ok { border: 1px solid #9CC7AE; background: #F4FAF6; }
.gate.no { border: 1px solid #D9A79A; background: #FCF0EC; }
.gate b { font-size: 14px; }
.gate.no b { color: #A24A38; }
.gate .note { margin: 4px 0 10px; }

/* A progress bar belongs under the box it is filling. */
.bar.zonebar { height: 3px; }

/* A duplicate pair reads as a pair. Grey rather than red: nothing is wrong with these rows, there
   are simply two of them, and one of the two is going to go. */
#rows tr.dupe td { background: #F1F2F4; }
#rows tr.dupe:hover td { background: #E9EBEE; }
#rows tr.dupe td.titlecell b { color: #5C6570; }
#rows tr.dupe.sel td { background: #E4E7EB; }
/* The copy whose file was deleted. A different colour from a track that was merely turned down,
   because the difference is not a matter of taste: there is no audio behind this row any more, so
   nothing here can play or be measured, and the row says that before anybody tries. */
#rows tr.gone td { background: #FBF0EE; color: #A08B87; }
#rows tr.gone td.titlecell b { color: #9E6B60; font-weight: 500; text-decoration: line-through; text-decoration-color: #D9B8B1; }
#rows tr.gone td.tickcol.yes { color: #C6ABA6; }
#rows tr.gone .play-one, #rows tr.gone td.numcol { opacity: .4; }
#rows tr.gone:hover td { background: #F7E7E3; }
#rows tr.gone.sel td { background: #F4E1DC; }

/* The other copy, shown rather than described. Two lines of identical text are not a choice; two
   covers and two release dates are. */
.twins { display: grid; gap: 8px; margin-top: 8px; }
.twin { display: grid; grid-template-columns: 76px 1fr; gap: 10px; align-items: start;
  border: 1px solid var(--surface-brd, #d7dde5); border-radius: var(--r-1, 8px); padding: 8px; }
.twin-cover { width: 76px; height: 76px; border-radius: 4px; overflow: hidden;
  background: var(--bg-bot, #eef1f5); display: flex; align-items: center; justify-content: center; }
.twin-cover img { width: 100%; height: 100%; object-fit: cover; }
.twin-cover .none { font-size: 10px; line-height: 1.3; text-align: center; color: var(--muted, #7b8794); padding: 4px; }
.twin-meta b { font-size: 13px; }
.twin.gone { background: #FBF0EE; border-color: #E3C6C1; }
.twin.gone .twin-meta b { text-decoration: line-through; text-decoration-color: #D9B8B1; }

/* The copy that carries more. Marked rather than merely listed, because the whole decision turns on
   it and counting characters by eye is not a decision procedure. */
.twin.this { margin-top: 8px; opacity: .9; }
.twin.fuller { border-color: #9CC7AE; background: #F4FAF6; }
.twin.fuller .twin-meta b::after { content: ' · carries more'; font-weight: 500; color: #3E8E6E; font-size: 11px; }

/* Voice and language: the pair a person checks by ear and a venue filters on, so they sit at the
   top of the panel with room to be corrected rather than buried in a list of measurements. */
.voicecard { border: 1px solid var(--surface-brd, #d7dde5); border-radius: var(--r-1, 8px);
  padding: 10px 12px; margin: 10px 0; background: var(--bg-bot, #fbfcfd); }
.voicecard.clash { border-color: #D9BC7A; background: #FCF8EE; }
.vc-head { font: 600 12px/1.4 var(--ui, inherit); letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted, #7b8794); margin-bottom: 6px; }
.vc-clash { text-transform: none; letter-spacing: 0; color: #8A6A22; font-weight: 600; }
.vc-claims { font-size: 12.5px; line-height: 1.55; }
.vc-claims .muted { display: inline-block; min-width: 74px; }
.vc-edit { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 8px;
  padding-top: 8px; border-top: 1px solid var(--surface-brd, #e6eaef); }
.vc-edit label { font-size: 11px; color: var(--muted, #7b8794); display: flex; gap: 5px; align-items: center; }
.vc-edit select, .vc-edit input { font-size: 12px; padding: 3px 6px; }
.vc-edit input { width: 90px; }
.vc-edit .note { margin: 0; color: #3E8E6E; }

/* Picking a handful of rows, the way an inbox does it. */
#rows th.pickcol, #rows td.pickcol, #tracks th.pickcol, #tracks td.pickcol {
  width: 30px; text-align: center; padding: 6px 0 6px 8px;
}
#rows td.pickcol input, #tracks td.pickcol input,
#rows th.pickcol input, #tracks th.pickcol input { cursor: pointer; margin: 0; }

/* The bar appears only once something is picked, and says the number before it says the verb -
   that is the thing a person checks before pressing anything that acts on more than one row. */
.pickbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  border: 1px solid #9CC7AE; background: #F4FAF6; border-radius: var(--r-1, 8px);
  padding: 8px 12px; margin-bottom: 8px; }
.pickbar b { font-size: 13px; margin-right: 4px; }
.pickbar .btn { padding: 4px 10px; font-size: 12px; }
#rows tr.picked td, #tracks tr.picked td { background: #EEF5FB; }
#rows tr.picked:hover td, #tracks tr.picked:hover td { background: #E6EFF8; }

/* The size of the delivery, said plainly under the table. Amber when rows are missing, because a
   list that is short and quiet about it is the one failure this console must never have. */
#rows-tally { margin-top: 8px; }
#rows-tally.warn { color: #C08A3E; font-weight: 600; }

/* ---------------------------------------------------------------- the release chain
   Four cards in a row on a wide screen, stacked on a narrow one, joined by a line so they read as
   one path rather than as four unrelated panels. The tint stops at the first unfinished step. */
.rel-chain { display: grid; gap: 12px; margin-top: 12px;
  /* four across whenever they fit: the point is that it is one path of four steps, and a step that
     wraps onto its own row stops looking like the next one */
  grid-template-columns: repeat(auto-fit, minmax(205px, 1fr)); }
.rel-step { position: relative; background: var(--a-card, #fff); border: 1px solid var(--a-brd, #dfe3e8);
  border-radius: 10px; padding: 14px 16px; }
.rel-step + .rel-step::before { content: ''; position: absolute; left: -13px; top: 50%;
  width: 12px; height: 2px; background: var(--a-brd, #dfe3e8); }
@media (max-width: 1100px) { .rel-step + .rel-step::before { display: none; } }
.rel-step.done { border-color: #4E9A5E; background: color-mix(in srgb, #4E9A5E 6%, transparent); }
.rel-step.here { border-color: #C08A3E; box-shadow: inset 0 0 0 1px #C08A3E; }
.rel-n { display: flex; align-items: baseline; gap: 8px; margin-bottom: 6px; }
.rel-n b { font-size: 23px; white-space: nowrap; line-height: 1; font-variant-numeric: tabular-nums; }
.rel-n span { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--a-muted, #6b7480); }
.rel-step .row { margin-top: 10px; }

/* ---------------------------------------------------------------- the workbench went away
   The console can now be opened from anywhere, which means the machine it talks to can vanish
   mid-session. A button that silently does nothing is worse than a locked screen. */
#offline { position: fixed; inset: 0; z-index: 9000; display: none;
  background: rgba(16, 23, 31, .82); backdrop-filter: blur(3px);
  align-items: center; justify-content: center; }
#offline.on { display: flex; }
#offline .box { max-width: 420px; background: #fff; color: #10171f; border-radius: 12px;
  padding: 26px 28px; text-align: center; box-shadow: 0 24px 60px rgba(0,0,0,.3); }
#offline h2 { margin: 0 0 8px; font-size: 18px; }
#offline p { margin: 0 0 6px; font-size: 13px; line-height: 1.5; color: #55606d; }

/* A button carries its own display, so the hidden attribute alone does not hide one. */
.btn[hidden], [hidden] { display: none !important; }
