/* Inter, self-hosted. Was loaded from fonts.googleapis.com, which sends every
   visitor's IP to Google on every page — a third-party transfer that cannot be
   reconciled with running no consent banner, and the source of the intermittent
   "failed to load" errors on the static pages. Same reason Tabler is local. */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('/fonts/inter-latin-400-normal.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap;
  src: url('/fonts/inter-latin-500-normal.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('/fonts/inter-latin-600-normal.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap;
  src: url('/fonts/inter-latin-700-normal.woff2') format('woff2'); }

:root {
  --bg: #292929;
  --panel: #333333;
  --panel-2: #3c3c3c;
  --border: #484848;
  --border-strong: #585858;
  --text: #ffffff;
  --text-dim: #b4b4b4;
  --text-faint: #787878;
  --accent: #aa38d8;
  --accent-dim: #7d29a8;
  --danger: #f34144;
  --radius: 8px;
  --mono: 'SF Mono', 'Roboto Mono', Consolas, monospace;
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-size: 14px;
  font-family: var(--font-sans);
}

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

button, input, select, textarea {
  font-family: inherit;
  font-size: 14px;
  color: var(--text);
}

input, select, textarea {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 8px 10px;
  outline: none;
}
input:focus, select:focus, textarea:focus { border-color: var(--accent-dim); }

button {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 8px 14px;
  cursor: pointer;
  color: var(--text);
}
button:hover { border-color: var(--border-strong); }
button:active { transform: scale(0.98); }
button.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #ffffff;
  font-weight: 600;
}
button.primary:hover { background: #bf53ed; border-color: #bf53ed; }
button.danger { color: var(--danger); border-color: var(--danger); }
button.danger:hover { background: rgba(243,65,68,0.12); }
button.subtle {
  background: transparent;
  border-color: transparent;
  color: var(--text-dim);
}
button.subtle:hover { color: var(--text); border-color: var(--border); }
button:disabled { opacity: 0.4; cursor: not-allowed; pointer-events: none; }

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 24px;
  border-bottom: 1px solid var(--border);
}
.topbar .brand { display: flex; align-items: center; }
.topbar .brand a { display: flex; align-items: center; }
.topbar .brand img { height: 28px; width: auto; }
.topbar .sub { color: var(--text-dim); font-size: 13px; }

/* Discourages right-click > Save image and drag-to-desktop on logos and artwork.
   This is a deterrent only: the image is still reachable via DevTools, the network
   tab and its direct URL. Do not treat it as protection. */
img.logo, .artist-logo, .sah-logo, .art img, .anim-card img, #logoPreview img,
.track-card .art img, .suggestion-art {
  -webkit-user-drag: none; user-select: none; -webkit-user-select: none;
  -webkit-touch-callout: none; pointer-events: none;
}

.container {
  max-width: 1100px;
  margin: 0 auto;
  padding: 14px 24px 80px;
}

.card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 18px 20px;
}

.label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-faint);
  margin-bottom: 6px;
  display: block;
}

.field { display: flex; flex-direction: column; margin-bottom: 12px; min-width: 0; }
.field input, .field textarea, .field select { width: 100%; min-width: 0; box-sizing: border-box; }

.row { display: flex; gap: 12px; }
.row > .field { flex: 1; min-width: 0; }
/* Inputs in a row line up, and the labels sit directly above them.
   Each .field is its own flex column, so a label wrapping to two lines pushed only that
   field's input down. Aligning each field's contents to the BOTTOM lines the inputs up
   with each other, and — unlike stretching the labels — leaves every label hard against
   its own input rather than floating at the top of a taller box. So a wrapped "Time
   signature" grows upwards, and "Key" and "BPM" keep their normal small gap. */
.row > .field { justify-content: flex-end; }

.empty {
  color: var(--text-faint);
  font-size: 13px;
  padding: 24px 8px;
  text-align: center;
  border: 1px dashed var(--border);
  border-radius: var(--radius);
}

.toast {
  position: fixed;
  top: 70px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--panel-2);
  border: 1px solid var(--border-strong);
  color: var(--text);
  padding: 9px 16px;
  border-radius: var(--radius);
  font-size: 13px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  z-index: 200;
}
.toast.show { opacity: 1; }

/* Track pool labels */
.track-label { display:inline-block; font-size:9px; font-weight:700; text-transform:uppercase;
  letter-spacing:0.05em; padding:1px 5px; border-radius:4px; margin-left:6px; vertical-align:middle; }
.label-dup { background:rgba(243,65,68,0.2); color:#f34144; border:1px solid #f34144; }
.label-ver { background:rgba(226,169,38,0.2); color:#e2a926; border:1px solid #e2a926; }
.track-card.in-setlist { opacity:0.4; }
.pool-sep { font-size:11px; color:var(--text-faint); padding:8px 4px 4px; letter-spacing:0.06em; text-transform:uppercase; border-top:1px solid var(--border); margin-top:4px; }


/* ---- Select menus --------------------------------------------------------
   Native selects render with the OS chrome, which looks foreign in a dark UI.
   The closed control is fully themed here; the OPEN list is drawn by the
   operating system and cannot be styled from CSS — only a custom JS listbox
   could change that, at the cost of keyboard and accessibility behaviour. */
select {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  background-color: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius, 8px);
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  padding: 7px 32px 7px 10px;
  cursor: pointer;
  /* Chevron drawn inline so no image request is needed */
  background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239a9aa6' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 9px center;
  background-size: 14px 14px;
  transition: border-color .15s, background-color .15s;
}
select:hover { border-color: var(--accent-dim); }
select:focus { outline: none; border-color: var(--accent); }
select:disabled { opacity: .5; cursor: not-allowed; }
/* Dark option rows where the browser honours it (Chrome/Edge on most platforms) */
select option { background: var(--panel); color: var(--text); }
select option:checked { background: var(--accent); color: #fff; }

/* ---- Custom dropdown (see select.js) --------------------------------------
   The native <select> stays in the DOM as the source of truth but is visually
   hidden; the button and menu below are what the user sees. */
.ms-select { position: relative; display: inline-block; width: 100%; }
.ms-select-native {
  position: absolute; opacity: 0; pointer-events: none; width: 100%; height: 100%;
  left: 0; top: 0; margin: 0;
}
.ms-select-btn {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; box-sizing: border-box;
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: var(--radius, 8px); color: var(--text);
  font-family: inherit; font-size: 13px; line-height: 1.25;
  padding: 7px 10px; cursor: pointer; text-align: left;
  transition: border-color .15s;
  /* Matches a text input: 8px padding + 1px border + a 13px/1.25 line box lands on 36px.
     select.js replaces the native control with this button, so any height set on the
     <select> itself is invisible — this is the only place the two can be lined up. */
  min-height: 36px;
}
.ms-select-btn:hover { border-color: var(--accent-dim); }
.ms-select-btn:focus { outline: none; border-color: var(--accent); }
.ms-select-btn:disabled { opacity: .5; cursor: not-allowed; }
.ms-select-btn.placeholder { color: var(--text-faint); }
.ms-select-btn svg { flex-shrink: 0; color: var(--text-faint); }
.ms-select-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ms-select-open .ms-select-btn { border-color: var(--accent); }

.ms-select-menu {
  position: fixed; z-index: 2000; overflow-y: auto;
  background: var(--panel); border: 1px solid var(--border-strong, var(--border));
  border-radius: 10px; padding: 4px;
  box-shadow: 0 16px 40px rgba(0,0,0,0.55);
}
.ms-select-item {
  padding: 7px 10px; border-radius: 6px; font-size: 13px; color: var(--text);
  cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ms-select-item:hover, .ms-select-item.active { background: var(--panel-2); }
.ms-select-item.selected { background: var(--accent); color: #fff; }
.ms-select-item.disabled { opacity: .4; cursor: default; }

/* ---- Checkboxes -----------------------------------------------------------
   One definition for the whole app. This lived inline on each checkbox, then in
   four separate page stylesheets, and each copy drifted — which is why the
   delete-account, delete-artist, register and remove-artist boxes all looked
   different. style.css is loaded by every page, so this is the only place it
   needs to exist. Add the class; do not add another inline style. */
.checkbox-row { display:flex; align-items:center; gap:8px; margin-bottom:12px; }
.checkbox-row.align-top { align-items:flex-start; }
.checkbox-row.align-top input[type="checkbox"] { margin-top:2px; }
.checkbox-row input[type="checkbox"] {
  width:16px; height:16px; cursor:pointer; accent-color:var(--accent);
  flex-shrink:0; color-scheme:dark; margin:0;
}
.checkbox-row label, .checkbox-row span { color:var(--text-dim); font-size:13px;
  cursor:pointer; line-height:1.4; }

/* ---- iOS-style toggle switch -------------------------------------------------
   A styled checkbox, not a div pretending to be one. The real <input> stays in the
   markup (visually hidden, not display:none) so it keeps its keyboard focus, its
   space-bar toggle and its announcement to screen readers — all of which a div would
   have to reimplement, badly. The track and knob are drawn from the checked state via
   :checked, so there is no JS keeping the visuals in sync. */
.sw { position: relative; display: inline-block; width: 38px; height: 22px; flex-shrink: 0; }
.sw input {
  position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0;
  cursor: pointer; z-index: 2;
}
.sw-track {
  position: absolute; inset: 0; border-radius: 999px;
  background: var(--panel-2); border: 1px solid var(--border);
  transition: background .18s ease, border-color .18s ease;
  pointer-events: none; display: block;
}
.sw-knob {
  position: absolute; top: 2px; left: 2px; width: 16px; height: 16px;
  border-radius: 50%; background: #d8d8d8;
  transition: transform .18s ease, background .18s ease;
}
.sw input:checked + .sw-track { background: var(--accent); border-color: var(--accent); }
.sw input:checked + .sw-track .sw-knob { transform: translateX(16px); background: #fff; }
.sw input:focus-visible + .sw-track { outline: 2px solid var(--accent); outline-offset: 2px; }
.sw input:disabled + .sw-track { opacity: .5; }

/* ---- Date fields ------------------------------------------------------------
   Used on Create link, Edit link, the copyright registration export, Edit setlist,
   setlist metadata and /admin. All of them inherit the generic `input` rule above,
   which leaves the browser's own date UI untouched — a white calendar panel and
   near-black digits on a dark field.

   `color-scheme: dark` is the important line, and it is the same trap as the
   checkboxes: without it the OS draws its picker in light mode however the field
   itself is styled. What can be reached from CSS is the field; the dropdown panel is
   drawn by the browser and only responds to color-scheme.
*/
input[type="date"],
input[type="datetime-local"],
input[type="month"],
input[type="time"] {
  color-scheme: dark;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius, 8px);
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  line-height: 1.25;
  padding: 8px 10px;
  min-height: 36px;              /* matches text inputs and .ms-select-btn */
  box-sizing: border-box;
  transition: border-color .15s;
}
input[type="date"]:hover,
input[type="datetime-local"]:hover,
input[type="month"]:hover,
input[type="time"]:hover { border-color: var(--accent-dim); }

input[type="date"]:focus,
input[type="datetime-local"]:focus,
input[type="month"]:focus,
input[type="time"]:focus { border-color: var(--accent); outline: none; }

/* An empty field shows the format hint (dd-mm-jjjj). At full contrast it reads as a
   real value; dimmed, it reads as a placeholder, which is what it is. */
input[type="date"]::-webkit-datetime-edit-text,
input[type="datetime-local"]::-webkit-datetime-edit-text { color: var(--text-faint); padding: 0 1px; }
input[type="date"]:invalid::-webkit-datetime-edit,
input[type="date"]:not(:focus)::-webkit-datetime-edit-day-field:not([aria-valuenow]),
input[type="date"]:not(:focus)::-webkit-datetime-edit-month-field:not([aria-valuenow]),
input[type="date"]:not(:focus)::-webkit-datetime-edit-year-field:not([aria-valuenow]) { color: var(--text-faint); }

/* The field that currently has the caret picks up the accent, so tabbing through
   day/month/year is visible rather than silent. */
input[type="date"]::-webkit-datetime-edit-day-field:focus,
input[type="date"]::-webkit-datetime-edit-month-field:focus,
input[type="date"]::-webkit-datetime-edit-year-field:focus,
input[type="time"]::-webkit-datetime-edit-hour-field:focus,
input[type="time"]::-webkit-datetime-edit-minute-field:focus {
  background: var(--accent);
  color: #fff;
  border-radius: 3px;
  outline: none;
}

/* The calendar glyph ships black. The filter recolours it to the brand purple rather
   than swapping in an image, which would need a second asset per state. */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator,
input[type="month"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator {
  cursor: pointer;
  opacity: 0.75;
  filter: invert(41%) sepia(83%) saturate(3200%) hue-rotate(274deg) brightness(93%) contrast(96%);
  transition: opacity .15s;
}
input[type="date"]::-webkit-calendar-picker-indicator:hover,
input[type="datetime-local"]::-webkit-calendar-picker-indicator:hover,
input[type="month"]::-webkit-calendar-picker-indicator:hover,
input[type="time"]::-webkit-calendar-picker-indicator:hover { opacity: 1; }

/* Firefox draws its own clear button; it inherits colour rather than staying black. */
input[type="date"]::-moz-calendar-picker-indicator { filter: invert(1); cursor: pointer; }

/* ---- Custom date panel (datepicker.js) ------------------------------------- */
.dp-panel {
  position: fixed; z-index: 14500;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 12px; padding: 10px;
  box-shadow: 0 16px 44px rgba(0,0,0,0.55);
  width: 268px; box-sizing: border-box;
  font-size: 13px; color: var(--text);
  animation: dpIn .12s ease;
}
@keyframes dpIn { from { opacity:0; transform:translateY(-6px); } to { opacity:1; transform:translateY(0); } }

.dp-head { display:flex; align-items:center; justify-content:space-between; gap:8px; margin-bottom:8px; }
.dp-month { font-weight:600; font-size:13px; }
.dp-nav {
  background:transparent; border:1px solid var(--border); border-radius:7px;
  color:var(--text-dim); cursor:pointer; width:28px; height:28px; line-height:1;
  font-size:15px; font-family:inherit; padding:0;
}
.dp-nav:hover { color:var(--text); border-color:var(--border-strong); }

.dp-dow { display:grid; grid-template-columns:repeat(7,1fr); gap:2px; margin-bottom:4px; }
.dp-dow span { text-align:center; font-size:10px; color:var(--text-faint); padding:4px 0; }

.dp-grid { display:grid; grid-template-columns:repeat(7,1fr); gap:2px; }
.dp-cell {
  background:transparent; border:1px solid transparent; border-radius:7px;
  color:var(--text); font-family:inherit; font-size:12px;
  height:32px; cursor:pointer; padding:0;
}
.dp-cell:hover:not(:disabled) { background:var(--panel-2); }
.dp-empty { visibility:hidden; }
/* Today is outlined, the selection is filled — so "where am I" and "what did I pick"
   never look like the same thing. */
.dp-today { border-color:var(--border-strong); }
.dp-sel { background:var(--accent); color:#fff; font-weight:600; }
.dp-sel:hover { background:var(--accent); }
.dp-off { opacity:.28; cursor:not-allowed; }

.dp-foot { display:flex; justify-content:space-between; gap:8px; margin-top:8px;
  padding-top:8px; border-top:1px solid var(--border); }
.dp-foot button {
  background:transparent; border:1px solid var(--border); border-radius:7px;
  color:var(--text-dim); font-family:inherit; font-size:12px;
  padding:5px 12px; cursor:pointer;
}
.dp-foot button:hover { color:var(--text); border-color:var(--border-strong); }

/* The native indicator is redundant once the panel is ours, and clicking it would open
   the browser's own picture of the same thing. */
@media (min-width: 821px) {
  input[type="date"]::-webkit-calendar-picker-indicator { display:none; }
  input[type="date"] { cursor:pointer; }
}

/* ---- Placeholders -----------------------------------------------------------
   Darker, and gone on focus.

   The default sat close enough to the real text colour to be mistaken for a value —
   people read a filled-in field and wondered why saving complained it was empty. And an
   example that stays put while you type over it is just noise behind the caret.
*/
input::placeholder,
textarea::placeholder {
  color: var(--text-faint);
  opacity: 0.55;          /* Firefox applies its own opacity; stated so both agree */
}
input:focus::placeholder,
textarea:focus::placeholder {
  color: transparent;
}

/* Safari overscroll. Rubber-banding past the top of a page showed the browser's own
   white behind it, in a strip under the shell header. The colour has to be on <html>:
   a background on <body> does not paint the overscroll area. overscroll-behavior stops
   the bounce reaching the shell and chaining the scroll up to it. */
html {
  background: var(--bg);
  overscroll-behavior-y: none;
}

/* Safari draws its own calendar button inside a date input on top of the app's picker,
   so every date field had two. Chrome shows nothing here, which is why it only appeared
   on Safari. */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator,
input[type="month"]::-webkit-calendar-picker-indicator,
input[type="week"]::-webkit-calendar-picker-indicator {
  display: none;
  -webkit-appearance: none;
}
input[type="date"]::-webkit-inner-spin-button,
input[type="date"]::-webkit-clear-button,
input[type="datetime-local"]::-webkit-inner-spin-button,
input[type="datetime-local"]::-webkit-clear-button {
  display: none;
  -webkit-appearance: none;
}

/* Safari renders a date input as its own control and opens a calendar on focus, on top
   of whatever the app draws. Hiding the indicator is not enough — the field itself is
   the trigger. -webkit-appearance:none takes the native control off, leaving the app's
   own styling and the typed segments, which is what every other browser already showed. */
input[type="date"],
input[type="datetime-local"],
input[type="time"],
input[type="month"],
input[type="week"] {
  -webkit-appearance: none;
  appearance: none;
}

/* A readonly date field is still the app's picker trigger, so it must not look disabled
   or lose its text cursor affordance. Set by datepicker.js on desktop only. */
input[type="date"]:read-only {
  cursor: pointer;
  opacity: 1;
}

/* The empty-setlist prompt tells you to drag tracks here. Once a track IS over the zone
   it has been read, and the drop indicator should take its place rather than appear
   below it. Removed from the flow, not just made invisible — visibility:hidden left the
   prompt's 70-odd pixels reserved and the incoming track landed underneath a blank band.
   The zone's own min-height keeps it a target while it is empty. */
.dropzone.dragover .empty { display: none; }
