@font-face {
  font-family: 'GT Era Text';
  src: url('/assets/fonts/GT-Era-Text-Regular-Trial.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'GT Era Text';
  src: url('/assets/fonts/GT-Era-Text-Medium-Trial.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'GT Era Text';
  src: url('/assets/fonts/GT-Era-Text-Bold-Trial.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* Client "Delivery" page fonts -- from the design handoff. Same trial
   restriction as the pair above (real GT Era, not yet licensed). Declaring
   each as a weight RANGE (matching the reference implementation) lets any
   weight number in that range resolve to the one face we have. */
@font-face {
  font-family: 'GT Era Text';
  src: url('/assets/fonts/GTEraText-Regular.otf') format('opentype');
  font-weight: 400;
  font-style: normal;
}
@font-face {
  font-family: 'GT Era Text';
  src: url('/assets/fonts/GTEraText-Medium.otf') format('opentype');
  font-weight: 500 600;
  font-style: normal;
}
@font-face {
  font-family: 'GT Era Text';
  src: url('/assets/fonts/GTEraText-Bold.otf') format('opentype');
  font-weight: 700 900;
  font-style: normal;
}
@font-face {
  font-family: 'GT Era Display';
  src: url('/assets/fonts-display/GTEraDisplay-Medium.otf') format('opentype');
  font-weight: 500 600;
  font-style: normal;
}
@font-face {
  font-family: 'GT Era Display';
  src: url('/assets/fonts-display/GTEraDisplay-Bold.otf') format('opentype');
  font-weight: 700;
  font-style: normal;
}
@font-face {
  font-family: 'GT Era Display';
  src: url('/assets/fonts-display/GTEraDisplay-Black.otf') format('opentype');
  font-weight: 800 900;
  font-style: normal;
}

:root {
  --bg: #0e0f12;
  --bg-elev: #17181d;
  --bg-elev-2: #1f2128;
  --border: #2a2c34;
  --text: #eef0f4;
  --text-dim: #9698a3;
  --accent: #6ee7c9;
  --accent-dim: #3ba888;
  --danger: #ef6b6b;
  --radius: 10px;

  /* Client "Delivery" page palette -- overridden per-project from the cover
     artwork at runtime (see paletteFromImage in test.js). These are the
     static fallback values from the design handoff. */
  --paper: #121212;
  --paper-alt: #1c1c1a;
  --ink: #f5f4f0;
  --d-accent: #3f6ee0;
  --d-accent-ink: #f5f4f0;
  --d-muted: #6d6858;
  --dock-muted: rgba(255,255,255,.6);
  --dock-hover: rgba(255,255,255,.95);
  font-size: 16px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: 'GT Era Text', -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, sans-serif;
  min-height: 100%;
}

body {
  min-height: 100vh;
}

a { color: var(--accent); }

.wrap {
  width: 100%;
  max-width: 640px;
}

h1 {
  font-size: 1.4rem;
  font-weight: 500;
  margin: 0 0 4px;
  text-align: center;
}

.subtitle {
  color: var(--text-dim);
  font-size: 0.9rem;
  margin: 0 0 28px;
  text-align: center;
}

.card {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px;
  margin-bottom: 20px;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--accent);
  color: #06251d;
  border: none;
  border-radius: 8px;
  padding: 10px 16px;
  font-size: 0.92rem;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.05s ease;
}

.btn:hover { background: #82f0d4; }
.btn:active { transform: scale(0.98); }

.btn:disabled {
  background: var(--bg-elev-2);
  color: var(--text-dim);
  cursor: not-allowed;
}

.btn.secondary {
  background: var(--bg-elev-2);
  color: var(--text);
  border: 1px solid var(--border);
}

.btn.secondary:hover { background: #262832; }

.btn.small {
  padding: 6px 12px;
  font-size: 0.8rem;
}

input[type="text"], input[type="password"] {
  width: 100%;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  color: var(--text);
  font-size: 0.95rem;
}

input[type="text"]:focus, input[type="password"]:focus {
  outline: none;
  border-color: var(--accent-dim);
}

label {
  display: block;
  font-size: 0.82rem;
  color: var(--text-dim);
  margin-bottom: 6px;
}

.track-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.track-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
  border-top: 2px solid transparent;
}

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

.track-row.dragging {
  opacity: 0.4;
}

.track-row.drag-over {
  border-top: 2px solid var(--accent);
}

.drag-handle {
  cursor: grab;
  color: var(--text-dim);
  flex-shrink: 0;
  font-size: 1rem;
  line-height: 1;
  user-select: none;
}

.drag-handle:active {
  cursor: grabbing;
}

.track-index {
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  width: 22px;
  flex-shrink: 0;
  text-align: right;
}

.track-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.92rem;
}

.track-name-input {
  flex: 1;
  min-width: 0;
  background: var(--bg-elev-2);
  border: 1px solid var(--accent-dim);
  border-radius: 6px;
  padding: 3px 8px;
  color: var(--text);
  font-size: 0.92rem;
  font-family: inherit;
}
.track-name-input:focus { outline: none; border-color: var(--accent); }

.track-rename {
  background: none;
  border: none;
  color: var(--text-dim);
  cursor: pointer;
  font-size: 0.85rem;
  line-height: 1;
  padding: 4px;
  flex-shrink: 0;
}
.track-rename:hover { color: var(--accent); }

.track-meta {
  color: var(--text-dim);
  font-size: 0.78rem;
  flex-shrink: 0;
}

.track-remove {
  background: none;
  border: none;
  color: var(--text-dim);
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  padding: 4px;
}
.track-remove:hover { color: var(--danger); }

.empty-state {
  color: var(--text-dim);
  font-size: 0.9rem;
  text-align: center;
  padding: 24px 0;
}

.row {
  display: flex;
  gap: 12px;
  align-items: center;
}

.row.between {
  justify-content: space-between;
}

.link-box {
  display: flex;
  gap: 8px;
  align-items: center;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 10px;
}

.link-box input {
  border: none;
  background: none;
  flex: 1;
  padding: 4px;
  font-size: 0.85rem;
  color: var(--accent);
}
.link-box input:focus { outline: none; }

.project-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
}
.project-item:last-child { border-bottom: none; }

.project-item .name { font-size: 0.92rem; }
.project-item .date { color: var(--text-dim); font-size: 0.78rem; }

.toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 10px 16px;
  border-radius: 8px;
  font-size: 0.85rem;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  z-index: 50;
}
.toast.show { opacity: 1; }

.gate {
  min-height: 60vh;
  display: flex;
  align-items: center;
  justify-content: center;
}
.gate .card { width: 100%; max-width: 340px; }

.badge {
  display: inline-block;
  font-size: 0.7rem;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--bg-elev-2);
  color: var(--text-dim);
  border: 1px solid var(--border);
}

.footer-note {
  color: var(--text-dim);
  font-size: 0.78rem;
  text-align: center;
  margin-top: 24px;
  line-height: 1.5;
}

/* Player-specific */
.player-header {
  text-align: center;
  margin-bottom: 24px;
}

.player-header h1 {
  font-size: 1.3rem;
}

.now-playing {
  text-align: center;
  margin-bottom: 8px;
}

.cover-art-hero {
  display: block;
  width: 100%;
  max-width: 320px;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  margin: 0 auto 20px;
}

.cover-preview {
  width: 88px;
  height: 88px;
  flex-shrink: 0;
  border-radius: 8px;
  border: 1px dashed var(--border);
  background: var(--bg-elev-2);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  color: var(--text-dim);
  font-size: 0.72rem;
  text-align: center;
}

.cover-preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.now-playing .title {
  font-size: 1.05rem;
  font-weight: 500;
}

.now-playing .status {
  color: var(--text-dim);
  font-size: 0.8rem;
  margin-top: 2px;
}

.transport {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
  margin: 18px 0 14px;
}

.transport button {
  background: none;
  border: none;
  color: var(--text);
  cursor: pointer;
  padding: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.transport button:hover { color: var(--accent); }

.transport .play-btn {
  background: var(--accent);
  color: #06251d;
  border-radius: 50%;
  width: 52px;
  height: 52px;
}
.transport .play-btn:hover { background: #82f0d4; color: #06251d; }

.progress-row {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.75rem;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

.progress-bar {
  flex: 1;
  height: 4px;
  background: var(--bg-elev-2);
  border-radius: 999px;
  position: relative;
  cursor: pointer;
  transition: height 0.1s ease;
}

.progress-bar:hover,
.progress-bar.scrubbing {
  height: 6px;
}

.progress-bar .fill {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  background: var(--accent);
  border-radius: 999px;
  width: 0%;
}

.progress-bar .fill::after {
  content: '';
  position: absolute;
  right: -5px;
  top: 50%;
  transform: translateY(-50%);
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent);
  opacity: 0;
  transition: opacity 0.1s ease;
}

.progress-bar:hover .fill::after,
.progress-bar.scrubbing .fill::after {
  opacity: 1;
}

.player-track-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 4px;
  border-bottom: 1px solid var(--border);
  border-radius: 6px;
  cursor: pointer;
}

.player-track-row:last-child { border-bottom: none; }
.player-track-row:hover { background: var(--bg-elev-2); }

.player-track-row.active .track-name { color: var(--accent); }

.download-link {
  background: none;
  border: none;
  font: inherit;
  color: var(--text-dim);
  cursor: pointer;
  flex-shrink: 0;
  padding: 4px;
  border-radius: 6px;
}
.download-link:hover { color: var(--accent); background: var(--bg-elev-2); }

.error-box {
  border: 1px solid var(--danger);
  background: rgba(239, 107, 107, 0.08);
  color: var(--danger);
  padding: 14px;
  border-radius: 8px;
  font-size: 0.88rem;
}

.spinner {
  width: 28px; height: 28px;
  border: 3px solid var(--bg-elev-2);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
  margin: 0 auto;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ================================================================
   CLIENT "DELIVERY" PAGE -- ported from the design handoff.
   Square corners everywhere, colors driven by --paper/--paper-alt/
   --ink/--d-accent (set per-project from the cover artwork; static
   fallbacks live in :root above).
   ================================================================ */

.delivery-page {
  position: relative;
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
  background: var(--paper);
  color: var(--ink);
  font-family: 'GT Era Text', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  font-variant-numeric: tabular-nums;
  padding-bottom: 128px;
}

.brand-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 20px;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.brand-right { display: flex; align-items: center; gap: 10px; }

/* Owner-only toolbar -- always visible (no gear/popover to open first),
   sitting right under the brand bar. Never shown in viewer mode. */
.owner-toolbar {
  padding: 0 20px 16px;
  border-bottom: 1px solid var(--paper-alt);
  margin-bottom: 4px;
}
.owner-toolbar-buttons { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.owner-toolbar-buttons .settings-btn { width: auto; flex: 1 1 150px; margin-bottom: 0; }
.settings-row { margin-bottom: 12px; }
.settings-row:last-child { margin-bottom: 0; }
.settings-row label {
  display: block;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--d-muted);
  margin-bottom: 6px;
}
.settings-inline { display: flex; gap: 6px; }
.settings-inline input {
  flex: 1 1 auto;
  min-width: 0;
  font: inherit;
  font-size: 13px;
  padding: 8px 9px;
  border: 1px solid var(--d-muted);
  background: transparent;
  color: var(--ink);
}
.settings-inline .settings-btn {
  width: auto;
  flex: 0 0 auto;
  margin-bottom: 0;
  white-space: nowrap;
}
.settings-btn {
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .04em;
  padding: 9px 11px;
  border: 1px solid var(--ink);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  width: 100%;
  margin-bottom: 6px;
}
.settings-btn:last-child { margin-bottom: 0; }
.settings-btn:hover { background: var(--ink); color: var(--paper); }
.settings-btn.primary { background: var(--ink); color: var(--paper); }
.settings-btn.primary:hover { background: var(--d-accent); color: var(--d-accent-ink); }
.settings-note {
  font-size: 11px;
  line-height: 1.5;
  color: var(--d-muted);
  margin: 8px 0 0;
}
.settings-note a { color: var(--d-muted); }
.settings-note-link { font-size: 11.5px; color: var(--d-muted); }

.theme-mode-buttons { display: flex; gap: 6px; }
.theme-mode-btn {
  flex: 1 1 0;
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  padding: 8px 6px;
  border: 1px solid var(--ink);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  text-align: center;
}
.theme-mode-btn:hover { background: var(--paper-alt); }
.theme-mode-btn.active { background: var(--ink); color: var(--paper); }

.artwork-block {
  position: relative;
  padding: 18px 20px 0;
  display: flex;
  justify-content: center;
}
.artwork-block img {
  width: 190px;
  height: 190px;
  object-fit: cover;
  display: block;
  background: var(--paper-alt);
}
.artwork-empty {
  width: 190px;
  height: 190px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--paper-alt);
  color: var(--d-muted);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.artwork-edit-overlay {
  position: absolute;
  top: 18px;
  left: 50%;
  transform: translateX(-50%);
  width: 190px;
  height: 190px;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  background: rgba(10,10,10,.55);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity .12s ease;
}
/* Only ever shown when the artwork block is explicitly marked editable
   (creator/owner view) -- a client viewing a shared link never gets this
   class, so hovering the artwork does nothing for them. */
.artwork-block.editable .artwork-edit-overlay { display: flex; }
.artwork-block.editable:hover .artwork-edit-overlay { opacity: 1; pointer-events: auto; }
.artwork-edit-overlay button {
  background: none;
  border: 0;
  color: #fff;
  font: inherit;
  font-size: 10.5px;
  text-decoration: underline;
  cursor: pointer;
}

.title-block { padding: 18px 20px 14px; }
.title-block h1 {
  margin: 0;
  font-family: 'GT Era Display', Helvetica, sans-serif;
  font-size: clamp(22px, 6.6vw, 36px);
  line-height: 1;
  font-weight: 900;
  letter-spacing: -.03em;
  text-transform: uppercase;
  white-space: nowrap;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
}
.artist-name {
  display: flex;
  justify-content: center;
  margin-top: 14px;
  font-family: 'GT Era Display', Helvetica, sans-serif;
  font-size: 22px;
  font-weight: 700;
  font-style: oblique 6deg;
  letter-spacing: .04em;
  text-transform: uppercase;
}

/* Inline-editable title/artist (owner/creator only). A client viewing a
   shared link never gets contenteditable set, so these rules are inert
   for them. */
[contenteditable="true"] {
  outline: none;
  cursor: text;
  border-radius: 0;
}
[contenteditable="true"]:hover, [contenteditable="true"]:focus {
  background: var(--paper-alt);
}
[contenteditable="true"]:empty:before {
  content: attr(data-placeholder);
  color: var(--d-muted);
  opacity: .6;
}
.spec-line {
  margin-top: 7px;
  text-align: center;
  font-family: 'GT Era Text', Helvetica, sans-serif;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--d-muted);
}
/* Turns green once the track that's about to play has actually finished
   loading -- a quick, honest signal that what you're about to hear really
   is the full lossless file, not still buffering in. */
.spec-lossless.ready { color: #2fae60; }

.spec-loading,
.spec-lossless {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  vertical-align: -1px;
}

/* A hard-edged bracket instead of a soft circle -- keeps the loading state
   in the same flat, no-radius language as the rest of the UI -- that spins
   continuously while the first track is being fetched/decoded. */
}

/* A tiny equalizer made of plain rectangles (no rounded bars, matching the
   site's hard-edge language). It only actually animates while audio is
   really playing -- sitting still (but still visible) the rest of the
   time, so the motion means something instead of just decorating. */
.soundwave-icon { flex: none; }
.soundwave-icon rect {
  transform-box: fill-box;
  transform-origin: center bottom;
}
.soundwave-icon.playing rect {
  animation: specWave 1s ease-in-out infinite;
}
.soundwave-icon rect:nth-child(1) { animation-delay: 0s; }
.soundwave-icon rect:nth-child(2) { animation-delay: .15s; }
.soundwave-icon rect:nth-child(3) { animation-delay: .3s; }
.soundwave-icon rect:nth-child(4) { animation-delay: .45s; }
@keyframes specWave {
  0%, 100% { transform: scaleY(.45); }
  50% { transform: scaleY(1); }
}

.action-grid {
  padding: 14px 20px 20px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.action-btn2 {
  padding: 15px 14px;
  font-family: 'GT Era Display', Helvetica, sans-serif;
  font-size: 14px;
  font-weight: 900;
  letter-spacing: .12em;
  text-transform: uppercase;
  text-align: center;
  border: 0;
  border-radius: 0;
  cursor: pointer;
}
.action-btn2.primary { background: var(--d-accent); color: var(--d-accent-ink); }
.action-btn2.primary:hover { filter: brightness(1.1); }
.action-btn2.secondary { background: transparent; border: 1px solid var(--ink); color: var(--ink); }
.action-btn2.secondary:hover { background: var(--ink); color: var(--paper); }

.delivery-tracks { list-style: none; margin: 0; padding: 0 20px; }
.delivery-track-row {
  position: relative;
  box-sizing: border-box;
  width: 100%;
  display: grid;
  grid-template-columns: 34px 1fr auto auto;
  align-items: center;
  gap: 14px;
  padding: 13px 12px;
  border: 0;
  border-radius: 0;
  text-align: left;
  cursor: pointer;
  font: inherit;
  background: transparent;
  color: var(--ink);
}
.delivery-track-row:hover:not(.active) { background: var(--paper-alt); }
.delivery-track-row.active { background: var(--d-accent); color: var(--d-accent-ink); }
.delivery-track-num {
  font-family: 'GT Era Display', Helvetica, sans-serif;
  font-size: 16.5px;
  font-weight: 900;
  letter-spacing: -.015em;
}
.delivery-track-name {
  font-size: 16.5px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.delivery-track-dur {
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: .04em;
}

/* Owner-only edit affordances -- a drag handle before the number, and
   rename/remove icons after the duration. Hidden until the row is hovered
   (or dragged) so the row looks identical to what a client sees the rest
   of the time. Never rendered at all in viewer mode. */
.delivery-track-row.editable { grid-template-columns: 26px 34px 1fr auto auto auto auto auto; }
.track-drag-handle,
.track-edit-icon {
  opacity: 0;
  font-size: 19px;
  line-height: 1;
  background: none;
  border: 0;
  padding: 7px;
  margin: -7px;
  color: inherit;
  cursor: pointer;
}
.track-drag-handle { cursor: grab; letter-spacing: -2px; }
.delivery-track-row.editable:hover .track-drag-handle,
.delivery-track-row.editable:hover .track-edit-icon,
.delivery-track-row.dragging .track-drag-handle {
  opacity: .6;
}
.track-edit-icon:hover { opacity: 1 !important; }
/* The folder icon is an SVG rather than a glyph, so it needs the same
   optical size as the ✎ and × beside it. */
.track-folder-icon { display: flex; align-items: center; padding: 8px 7px; }
.track-folder-icon .folder-glyph { width: 15px; height: 12.5px; }
/* The per-track download arrow. Shown to clients as well as the owner:
   faint until the row is hovered, then solid on its own hover, so a row
   still reads as a single line until someone reaches for it. On a touch
   screen there is no hover, so it stays quietly visible. */
.track-download-icon {
  display: flex;
  align-items: center;
  opacity: 0;
  background: none;
  border: 0;
  padding: 7px;
  margin: -7px;
  color: inherit;
  cursor: pointer;
  transition: opacity .15s;
}
.track-download-icon .download-glyph { width: 16px; height: 16px; display: block; }
.delivery-track-row:hover .track-download-icon { opacity: .6; }
.track-download-icon:hover { opacity: 1 !important; }
@media (hover: none) {
  .track-download-icon { opacity: .45; }
}
.delivery-track-row.drag-over { box-shadow: inset 0 2px 0 var(--ink); }
.delivery-track-row.dragging { opacity: .4; }
.delivery-track-name[contenteditable="true"] { cursor: text; white-space: nowrap; }

/* ---------------------------------------------------------------- folders
   Folder rows share the track row's metrics so the list reads as one
   column, but are never numbered and never become "active" -- they are
   navigation, not something that plays. */
.delivery-folder-row {
  position: relative;
  box-sizing: border-box;
  width: 100%;
  display: grid;
  grid-template-columns: 34px 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 13px 12px;
  cursor: pointer;
  color: var(--ink);
}
.delivery-folder-row:hover { background: var(--paper-alt); }
/* A little air where the tracks end and the folders begin, so the two
   groups read as separate without needing a rule or a heading. */
.delivery-track-row + .delivery-folder-row { margin-top: 14px; }
/* In the editor every track row carries a drag handle in front of its
   number, so folder rows need the same empty column or the two kinds of
   row would sit on different left edges. */
.delivery-folder-row.editable { grid-template-columns: 26px 34px 1fr auto; }
.delivery-folder-row.editable .delivery-folder-icon { grid-column: 2; }
.delivery-folder-row .delivery-track-name { font-weight: 600; }
.delivery-folder-row .delivery-track-dur { opacity: .55; }
.delivery-folder-icon { display: flex; align-items: center; }
.folder-glyph { display: block; }
/* Dropping a dragged track onto a folder moves it in -- outlined rather
   than the top-edge line reordering uses, so the two gestures never look
   like the same thing. */
.delivery-folder-row.folder-drop { box-shadow: inset 0 0 0 2px var(--ink); }

/* Doubles as the way back out, so the tap targets are sized for a thumb
   rather than for a caption. */
.folder-crumbs {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
  padding: 2px 26px 8px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.folder-crumb-back {
  font-family: 'GT Era Display', Helvetica, sans-serif;
  font-size: 20px;
  line-height: 1;
  padding: 0 2px;
  opacity: .55;
}
.folder-crumb {
  background: none;
  border: 0;
  padding: 8px 6px;
  font: inherit;
  color: inherit;
  opacity: .55;
  cursor: pointer;
}
.folder-crumb:hover { opacity: 1; }
.folder-crumb.current { opacity: 1; cursor: default; }
.folder-crumb.folder-drop { opacity: 1; box-shadow: inset 0 0 0 2px var(--ink); }
.folder-crumb-sep { opacity: .35; }

/* The move-to-folder field, opened from a row's folder icon. Sits inside
   the row it belongs to so there is no doubt which track is moving. */
.folder-picker {
  position: absolute;
  left: 12px;
  right: 12px;
  top: 100%;
  z-index: 5;
  display: flex;
  gap: 6px;
  padding: 8px;
  background: var(--paper);
  box-shadow: 0 0 0 1px var(--ink);
  cursor: default;
}
.folder-picker.above { top: auto; bottom: 100%; }

/* Picked-out tracks. Distinct from the active (playing) row, which uses the
   accent colour -- you can have one row playing and others selected. */
.delivery-track-row.selected:not(.active) { background: var(--paper-alt); box-shadow: inset 2px 0 0 var(--ink); }
.delivery-track-row.selected.active { box-shadow: inset 2px 0 0 var(--d-accent-ink); }

.selection-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 20px 8px;
  padding: 9px 12px;
  background: var(--paper-alt);
}
.selection-count {
  white-space: nowrap;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  margin-right: auto;
}
.selection-btn {
  font: inherit;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: 6px 10px;
  border: 1px solid var(--ink);
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  cursor: pointer;
}
.selection-btn:hover { background: var(--ink); color: var(--paper); }

/* Right-click menu, and the little "name a folder" box, which share a
   frame so the two never look like different parts of the app. */
.row-menu {
  position: fixed;
  z-index: 60;
  min-width: 210px;
  padding: 4px;
  background: var(--paper);
  color: var(--ink);
  box-shadow: 0 0 0 1px var(--ink), 0 10px 30px rgba(0,0,0,.35);
}
.row-menu-item {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  font-size: 13.5px;
  padding: 8px 10px;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: inherit;
  cursor: pointer;
}
.row-menu-item:hover { background: var(--ink); color: var(--paper); }
.row-menu-item.danger:hover { background: #b23a3a; color: #fff; }
.row-menu-sep { height: 1px; margin: 4px 0; background: var(--ink); opacity: .2; }

.folder-prompt { min-width: 260px; padding: 12px; }
.folder-prompt-label {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  opacity: .7;
  margin-bottom: 8px;
}
.folder-prompt .folder-picker-input { width: 100%; }
.folder-prompt-actions { display: flex; gap: 6px; margin-top: 8px; }
.folder-picker-input {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-size: 13.5px;
  padding: 6px 8px;
  border: 1px solid var(--ink);
  border-radius: 0;
  background: var(--paper);
  color: var(--ink);
}
.folder-picker-btn {
  font: inherit;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: 6px 10px;
  border: 1px solid var(--ink);
  border-radius: 0;
  cursor: pointer;
}
.folder-picker-btn.save { background: var(--ink); color: var(--paper); }
.folder-picker-btn.cancel { background: transparent; color: var(--ink); }

.add-tracks-row {
  padding: 4px 20px 8px;
  display: flex;
  align-items: center;
  gap: 12px;
}
.add-tracks-row button {
  font: inherit;
  font-family: 'GT Era Text', Helvetica, sans-serif;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--d-muted);
  background: none;
  border: 1px dashed var(--d-muted);
  padding: 10px 14px;
  cursor: pointer;
  flex: 1;
}
.add-tracks-row button:hover { color: var(--ink); border-color: var(--ink); }
/* Adding tracks is the main act; making a folder is occasional, so it takes
   only the width of its own label. */
#newFolderBtn { flex: 0 0 auto; }
.add-tracks-row { flex-wrap: wrap; }
.add-tracks-row button { white-space: nowrap; }
/* Status text takes its own line rather than squeezing the buttons into
   three-line labels while a mirror is running. */
.add-tracks-row .chooser-status:not(:empty) { flex-basis: 100%; }
.add-tracks-row button:disabled { opacity: .5; cursor: default; }
.chooser-status {
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--d-muted);
}
.delivery-empty-state {
  padding: 8px 20px 4px;
  text-align: center;
  font-size: 12.5px;
  color: var(--d-muted);
}

.contact-row {
  padding: 20px;
  /* A little more air between the last track and the contact details, so
     the two don't read as one continuous block. */
  margin-top: 30px;
  display: flex;
  gap: 18px;
  align-items: center;
  justify-content: center;
}
.contact-row img {
  width: 84px;
  height: 84px;
  flex-shrink: 0;
  object-fit: cover;
  object-position: 50% 32%;
}
.contact-col { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.contact-col .name {
  font-family: 'GT Era Display', Helvetica, sans-serif;
  font-size: 15px;
  font-weight: 900;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.contact-links { display: flex; flex-direction: column; gap: 4px; font-size: 12.5px; font-weight: 500; }
.contact-links a { color: var(--ink); text-decoration: none; }
.contact-links a:hover { opacity: .6; }

.security-note {
  margin: 0;
  padding: 4px 20px 22px;
  text-align: center;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--d-muted);
  line-height: 1.7;
}

.dock {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  background: var(--d-accent);
  color: var(--d-accent-ink);
  padding: 14px 20px 18px;
  display: flex;
  justify-content: center;
  z-index: 20;
}
.dock-inner {
  width: 100%;
  max-width: 560px;
  display: flex;
  align-items: center;
  gap: 18px;
}
.dock-play {
  width: 58px;
  height: 58px;
  flex-shrink: 0;
  background: var(--paper);
  color: var(--ink);
  font-size: 16px;
  font-weight: 900;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 0;
  cursor: pointer;
}
.dock-play:hover { filter: brightness(1.06); }
.dock-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 9px; }
.dock-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 12px;
}
.dock-arrow {
  background: none;
  border: 0;
  color: var(--dock-muted);
  font-size: 11px;
  padding: 4px;
  letter-spacing: -.05em;
  cursor: pointer;
}
.dock-arrow:hover { color: var(--dock-hover); }
.dock-track-name {
  font-size: 16px;
  font-weight: 700;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dock-scrubber { height: 18px; display: flex; align-items: center; cursor: pointer; }
.dock-scrubber-track { position: relative; width: 100%; height: 14px; background: var(--ink); }
.dock-scrubber-fill {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  background: var(--paper);
  width: 0%;
}
.dock-scrubber-handle {
  position: absolute;
  top: 50%;
  left: 0%;
  width: 22px;
  height: 22px;
  background: var(--d-accent);
  transform: translate(-50%, -50%);
  box-shadow: 0 0 0 3px var(--paper);
}
.dock-times {
  display: flex;
  justify-content: space-between;
  font-size: 10.5px;
  font-weight: 500;
  color: var(--dock-muted);
}

/* ================================================================ owner side
   The library and sign-in deliberately do NOT follow the artwork-derived
   palette the delivery page uses -- that one shifts per project, which would
   make the owner's own workspace change colour every time. This is a fixed,
   warm paper-and-ink scheme drawn from the same family, so it reads as part
   of the player rather than a separate admin tool. */
:root {
  --lib-paper: #f6f2ea;
  --lib-paper-alt: #ece5d9;
  --lib-card: #fffdf9;
  --lib-ink: #17150f;
  --lib-ink-dim: #6d6858;
  --lib-line: #ded5c5;
  --lib-accent: #17150f;
}

/* ---------------------------------------------------------------- sign-in */
.gate-screen {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: var(--lib-paper);
  color: var(--lib-ink);
}

.gate-card {
  width: 100%;
  max-width: 330px;
  background: var(--lib-card);
  border: 1px solid var(--lib-line);
  padding: 34px 30px;
}

.gate-title {
  /* Caps, matching the brand bar and the contact block, so the name reads
     the same everywhere it appears. */
  text-transform: uppercase;
  letter-spacing: .01em;
  font-family: 'GT Era Display', 'GT Era Text', sans-serif;
  font-size: 23px;
  font-weight: 700;
  margin: 0 0 4px;
  letter-spacing: -0.01em;
  color: var(--lib-ink);
}

.gate-sub {
  margin: 0 0 22px;
  font-size: 13px;
  color: var(--lib-ink-dim);
}

.gate-form { display: flex; flex-direction: column; gap: 9px; }

.gate-form input {
  width: 100%;
  padding: 11px 12px;
  background: var(--lib-paper);
  border: 1px solid var(--lib-line);
  color: var(--lib-ink);
  font-family: inherit;
  font-size: 14px;
}

.gate-form input:focus { outline: none; border-color: var(--lib-ink); }

.gate-form button {
  padding: 11px 14px;
  background: var(--lib-ink);
  color: var(--lib-paper);
  border: none;
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 700;
  cursor: pointer;
}

.gate-form button:disabled { opacity: .55; cursor: default; }

.gate-error {
  margin: 13px 0 0;
  min-height: 16px;
  font-size: 12.5px;
  color: #a4342b;
}

/* ---------------------------------------------------------------- library */
.library-screen {
  min-height: 100vh;
  background: var(--lib-paper);
  color: var(--lib-ink);
}

.library-screen .brand-bar {
  background: transparent;
  color: var(--lib-ink);
  border-bottom: 1px solid var(--lib-line);
}

.library-signout { cursor: pointer; color: var(--lib-ink-dim); }
.library-signout:hover { color: var(--lib-ink); }

.library-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 30px 20px 10px;
}

.library-title {
  font-family: 'GT Era Display', 'GT Era Text', sans-serif;
  font-size: 34px;
  font-weight: 700;
  margin: 0;
  letter-spacing: -0.015em;
  color: var(--lib-ink);
}

.library-actions { display: flex; align-items: center; gap: 9px; }

.library-view-toggle { display: flex; border: 1px solid var(--lib-line); }

.view-toggle-btn {
  padding: 7px 13px;
  background: transparent;
  border: none;
  color: var(--lib-ink-dim);
  font-family: inherit;
  font-size: 12.5px;
  cursor: pointer;
}

.view-toggle-btn.active { background: var(--lib-ink); color: var(--lib-paper); }

.library-new-btn {
  padding: 8px 15px;
  background: var(--lib-ink);
  color: var(--lib-paper);
  border: none;
  font-family: inherit;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}

.library-search-row { padding: 12px 20px 16px; }

.library-search {
  width: 100%;
  max-width: 420px;
  padding: 10px 12px;
  background: var(--lib-card);
  border: 1px solid var(--lib-line);
  color: var(--lib-ink);
  font-family: inherit;
  font-size: 14px;
}

.library-search:focus { outline: none; border-color: var(--lib-ink); }
.library-search::placeholder { color: var(--lib-ink-dim); }

.library-body { padding: 0 20px 48px; }

.library-status { color: var(--lib-ink-dim); font-size: 13.5px; margin: 8px 0 0; }

/* -- grid ---------------------------------------------------------------- */
.library-items.view-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 18px;
}

.view-grid .library-card {
  position: relative;
  background: var(--lib-card);
  border: 1px solid var(--lib-line);
  cursor: pointer;
  text-align: left;
  padding: 0;
  font-family: inherit;
  color: inherit;
  display: block;
  width: 100%;
}

.view-grid .library-card:hover { border-color: var(--lib-ink); }

.view-grid .library-card-art,
.view-grid .library-card-empty-art {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  display: block;
  background: var(--lib-paper-alt);
}

.view-grid .library-card-empty-art {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--lib-ink-dim);
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.view-grid .library-card-body { padding: 12px 13px 15px; }

.view-grid .library-card-title {
  font-size: 15px;
  font-weight: 700;
  margin: 0 0 3px;
  color: var(--lib-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.view-grid .library-card-artist {
  font-size: 13px;
  color: var(--lib-ink-dim);
  margin: 0 0 8px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.view-grid .library-card-meta { font-size: 11.5px; color: var(--lib-ink-dim); margin: 0; }

/* -- list ---------------------------------------------------------------- */
.library-items.view-list { display: block; border-top: 1px solid var(--lib-line); }

.view-list .library-card {
  position: relative;
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 12px 4px;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--lib-line);
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  color: inherit;
}

.view-list .library-card:hover { background: var(--lib-card); }

.view-list .library-card-art,
.view-list .library-card-empty-art {
  width: 40px; height: 40px; flex: none;
  object-fit: cover;
  background: var(--lib-paper-alt);
}

.view-list .library-card-empty-art { display: none; }

.view-list .library-card-body {
  flex: 1; min-width: 0;
  display: flex; align-items: baseline; gap: 10px;
}

.view-list .library-card-title {
  font-size: 14.5px; font-weight: 700; margin: 0; color: var(--lib-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.view-list .library-card-artist {
  font-size: 13px; color: var(--lib-ink-dim); margin: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.view-list .library-card-meta { font-size: 12px; color: var(--lib-ink-dim); margin: 0; flex: none; }

/* -- copy-link button ----------------------------------------------------
   Lets a link be grabbed straight from the library, without opening the
   delivery -- the common case when telling a client about a revision. */
.library-copy-btn {
  flex: none;
  border: 1px solid var(--lib-line);
  background: var(--lib-card);
  color: var(--lib-ink-dim);
  font-family: inherit;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.03em;
  padding: 6px 10px;
  cursor: pointer;
}

.library-copy-btn:hover { border-color: var(--lib-ink); color: var(--lib-ink); }
.library-copy-btn.copied { background: var(--lib-ink); color: var(--lib-paper); border-color: var(--lib-ink); }

.view-grid .library-copy-btn {
  position: absolute;
  top: 9px;
  right: 9px;
  opacity: 0;
  transition: opacity .12s linear;
}

.view-grid .library-card:hover .library-copy-btn,
.view-grid .library-copy-btn:focus-visible,
.view-grid .library-copy-btn.copied { opacity: 1; }

.view-list .library-copy-btn { margin-left: 10px; }

@media (hover: none) {
  .view-grid .library-copy-btn { opacity: 1; }
}

/* Nothing in the library may exceed the viewport width. Long titles, the
   search field and the action row were each able to push the page wider than
   the screen on a phone, which made the whole layout scroll sideways. */
.library-screen { overflow-x: hidden; }
.library-items, .library-card, .library-card-body { min-width: 0; max-width: 100%; }

@media (max-width: 560px) {
  .library-header {
    padding: 20px 16px 8px;
    /* Title on its own line, controls beneath it -- side by side they were
       wider than a phone screen. */
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }
  .library-title { font-size: 26px; text-align: left; }
  .library-actions { justify-content: space-between; width: 100%; }
  .library-search-row { padding: 0 16px 14px; }
  .library-search { max-width: 100%; }
  .library-body { padding: 0 16px 40px; }
  .library-items.view-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 12px; }

  /* Stacked so a long title never forces the row wider than the screen. */
  .view-list .library-card { flex-wrap: wrap; gap: 10px; }
  .view-list .library-card-body { flex-direction: column; align-items: flex-start; gap: 1px; min-width: 0; }
  .view-list .library-card-title,
  .view-list .library-card-artist { max-width: 100%; }
  .view-list .library-copy-btn,
  .view-list .library-delete-btn { margin-left: 0; }
}

/* ------------------------------------------------------- autosave status bar
   Replaces the old "save and get a link" button. Everything saves on its own,
   so what matters is being told when it's safe to send the link on. */
.save-bar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 16px;
  /* Uses the project's own artwork-derived palette, not the library's fixed
     one. This bar sits inside the delivery page, so a fixed colour here
     would cut a foreign stripe across an otherwise cohesively tinted page
     and make the artwork colours read as weaker than they are. */
  background: var(--paper-alt);
  border-top: 1px solid rgba(255, 255, 255, .10);
  color: var(--ink);
  font-size: 13px;
}

.save-bar-status { display: flex; align-items: center; gap: 7px; flex: 1; min-width: 0; }

.save-bar-dot {
  width: 7px; height: 7px; flex: none;
  background: var(--lib-ink-dim);
  border-radius: 50%;
}

.save-bar.is-saving .save-bar-dot { background: #c98a2b; animation: savePulse 1s ease-in-out infinite; }
.save-bar.is-saved .save-bar-dot { background: #3d8b5f; }
.save-bar.is-error .save-bar-dot { background: #a4342b; }

@keyframes savePulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }

.save-bar-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.save-bar-copy {
  flex: none;
  padding: 8px 14px;
  background: var(--d-accent);
  color: var(--d-accent-ink);
  border: none;
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 700;
  cursor: pointer;
}

.save-bar-copy:disabled { opacity: .4; cursor: default; }
.save-bar-copy.copied { background: #3d8b5f; }

/* Keeps the transport dock clear of the status bar. */
body.has-save-bar .dock { bottom: 46px; }

/* -- delete ---------------------------------------------------------------
   Sits beside the copy button but styled apart from it: destructive, and
   only commits on a second, deliberate click. */
.library-delete-btn {
  flex: none;
  border: 1px solid var(--lib-line);
  background: var(--lib-card);
  color: var(--lib-ink-dim);
  font-family: inherit;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.03em;
  padding: 6px 10px;
  cursor: pointer;
}

.library-delete-btn:hover { border-color: #a4342b; color: #a4342b; }

.library-delete-btn.armed {
  background: #a4342b;
  border-color: #a4342b;
  color: var(--lib-paper);
}

.library-delete-btn:disabled { opacity: .55; cursor: default; }

.view-grid .library-delete-btn {
  position: absolute;
  top: 9px;
  left: 9px;
  opacity: 0;
  transition: opacity .12s linear;
}

.view-grid .library-card:hover .library-delete-btn,
.view-grid .library-delete-btn:focus-visible,
.view-grid .library-delete-btn.armed,
.view-grid .library-delete-btn:disabled { opacity: 1; }

.view-list .library-delete-btn { margin-left: 8px; }

@media (hover: none) {
  .view-grid .library-delete-btn { opacity: 1; }
}

/* ------------------------------------------------------------- editor back
   The way out of a delivery, in the one place that's visible no matter how
   far down the track list you've scrolled. Browser Back and the trackpad
   swipe do the same thing; this exists because the installed app on iPhone
   has no browser chrome to fall back on. */
.brand-bar-left {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
}

.brand-back {
  flex: none;
  color: inherit;
  opacity: .62;
  text-decoration: none;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

.brand-back:hover { opacity: 1; }

@media (max-width: 480px) {
  .brand-bar-left { gap: 10px; }
  /* On a phone the back link and the page label are enough; the studio name
     would only wrap onto a second line and push the bar out of shape. It
     stays for clients, who have no back link and need the attribution. */
  .brand-bar-left.has-back > span { display: none; }
}

/* --------------------------------------------------- per-track mirror state
   Replaces the track number while that track is being copied into R2. Built
   once per render and never rewritten in place, so the rotation runs
   smoothly instead of restarting. */
.delivery-track-num.mirroring {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.mirror-spinner {
  display: inline-block;
  width: 11px;
  height: 11px;
  border: 1.5px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  opacity: .75;
  animation: mirrorSpin .8s linear infinite;
}

@keyframes mirrorSpin {
  to { transform: rotate(360deg); }
}

.delivery-track-num.mirror-failed { opacity: .45; }

/* ------------------------------------------------------------- first paint
   The app is hidden until whatever screen is being opened has its real
   content -- for a delivery that means its artwork, its palette and its
   tracks. The page background still shows, so the wait is a plain colour
   rather than an empty player with the wrong colours in it.

   Opacity rather than display: the layout is still measured, so nothing
   has to be recalculated at the moment of reveal. */
html.booting body > div { opacity: 0; }
body > div { opacity: 1; transition: opacity .2s ease; }
/* Someone who would rather not see things fade gets it instantly. */
@media (prefers-reduced-motion: reduce) {
  body > div { transition: none; }
}

/* ------------------------------------------------------- delivery password */
/* The toolbar uppercases its labels; this one is a sentence, so it opts
   out -- and needs the extra specificity to do it. */
.owner-toolbar label.settings-check,
.owner-toolbar label.settings-check span {
  text-transform: none;
  letter-spacing: .01em;
  font-size: 12.5px;
  color: var(--ink);
  opacity: .85;
  margin-bottom: 0;
}
.settings-check {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: .02em;
  text-transform: none;
  cursor: pointer;
}
.settings-check input { width: 15px; height: 15px; accent-color: var(--ink); cursor: pointer; }
.settings-note.is-locked { color: var(--ink); opacity: .85; }
/* The lock badge in the library, so it is obvious at a glance which
   deliveries a client needs a password for. */
.library-lock {
  display: inline-block;
  margin-left: 6px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  opacity: .6;
}

/* The lock screen stacks the card and the contact details, so anyone who
   has the link but not the password can see who to ask. */
#lockScreen { flex-direction: column; }
.contact-row.on-lock-screen {
  margin-top: 4px;
  max-width: 330px;
  width: 100%;
  gap: 14px;
}
.contact-row.on-lock-screen img { width: 62px; height: 62px; }
/* The contact block is styled for a delivery's own palette, where the ink
   is light on a dark page. The lock screen has no delivery and so no
   palette -- it uses the library's light one, and the text has to follow
   or it reads as white on cream. */
.contact-row.on-lock-screen,
.contact-row.on-lock-screen .name,
.contact-row.on-lock-screen a { color: var(--lib-ink); }
.contact-row.on-lock-screen a { opacity: .75; }
.contact-row.on-lock-screen a:hover { opacity: 1; }
