/* Palette adopted from bs-coolscan (dark, layered grays + blue accents). */
:root {
  --bg: #1a1d21;
  --surface: #23262c;
  --surface-2: #1e2228;
  --tile: #2b2f36;
  --hover: #2c313a;
  --border: #2a2e34;
  --border-strong: #383d44;
  --fg: #e6e6e6;
  --fg-bright: #f2f4f8;
  --fg-dim: #8a8f95;
  --label: #cdd6e0;
  --accent: #7fb4f0;
  --accent-fill: #37495f;
  --accent-fill-hi: #3f5168;
  --accent-bd: #4a6080;
  --danger: #e07a7a;
  --radius: 8px;
  --radius-sm: 6px;

  color-scheme: dark;
  font-family: system-ui, -apple-system, sans-serif;
  line-height: 1.5;
  color: var(--fg);
  -webkit-text-size-adjust: 100%;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  background: var(--bg);
}

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

h1 {
  color: var(--fg-bright);
  font-size: clamp(1.25rem, 5vw, 1.6rem);
  margin: 0 0 0.15rem;
}

button {
  font: inherit;
  cursor: pointer;
}

.error {
  color: var(--danger);
}

/* --- Top bar --------------------------------------------------------------- */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  border-bottom: 1px solid var(--border);
  padding: 0;
  height: 52px;
  background: var(--surface-2);
}

.topbar > a {
  font-weight: 700;
  text-decoration: none;
  color: var(--fg-bright);
  flex: none;
}

.topbar-auth {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.topbar-email {
  color: var(--fg-dim);
  font-size: 0.85rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 22ch;
}

.topbar-loading {
  color: var(--fg-dim);
  font-size: 0.85rem;
}

.topbar-signin {
  display: inline-flex;
  align-items: center;
  height: 34px;
  padding: 0 0.9rem;
  border: 1px solid var(--accent-bd);
  border-radius: var(--radius-sm);
  background: var(--accent-fill);
  color: var(--fg-bright) !important;
  font-size: 0.85rem;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}

.topbar-signin:hover {
  background: var(--accent-fill-hi);
}

.container {
  max-width: 64rem;
  margin: 1rem auto 4rem;
  padding: 0 1rem;
}

/* --- Auth ------------------------------------------------------------------ */
.signin {
  padding: 3rem 0;
  text-align: center;
  color: var(--fg-dim);
}

.logout {
  height: 34px;
  padding: 0 0.7rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--fg-dim);
  font-size: 0.85rem;
}

.logout:hover {
  border-color: var(--danger);
  color: var(--danger);
}

/* --- Album list (home) ----------------------------------------------------- */
.album-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: 1rem;
  margin-top: 1rem;
}

.album-card {
  display: block;
  text-decoration: none;
  color: inherit;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  transition: border-color 0.15s, transform 0.15s;
}

.album-card:hover,
.album-card:active {
  border-color: var(--accent-bd);
  transform: translateY(-2px);
}

.album-cover {
  display: block;
  width: 100%;
  aspect-ratio: 5 / 4;
  object-fit: cover;
  background: var(--tile);
}

.album-meta {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 0.6rem 0.8rem;
}

.album-title {
  font-weight: 600;
  color: var(--label);
}

.album-count {
  color: var(--fg-dim);
  font-size: 0.85rem;
}

/* --- Course banner (narrow screens only) ------------------------------------ */
.album-banner {
  display: none;
}

/* --- Album header ---------------------------------------------------------- */
.album-header {
  margin-top: 1rem;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}

.album-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  justify-content: flex-end;
}

.confirm-delete {
  color: var(--danger);
  font-size: 0.85rem;
  font-weight: 600;
}

/* --- Share QR -------------------------------------------------------------- */
.album-title-wrap {
  position: relative;
  display: inline-block;
  border-radius: var(--radius-sm);
}

.album-title-wrap:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
}

.qr-pop {
  position: absolute;
  top: calc(100% + 0.5rem);
  left: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity 0.12s ease, transform 0.12s ease, visibility 0.12s;
}

.album-title-wrap:hover .qr-pop,
.album-title-wrap:focus-within .qr-pop {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

/* Dark-on-white regardless of theme: an inverted QR does not scan reliably. */
.qr {
  display: block;
  border-radius: 4px;
}

.qr-url {
  max-width: 15rem;
  overflow-wrap: anywhere;
  color: var(--fg-dim);
  font-size: 0.75rem;
  text-align: center;
}

@media (prefers-reduced-motion: reduce) {
  .qr-pop {
    transition: none;
  }
}

.album-headtext {
  min-width: 0;
}

.album-sub {
  margin: 0 0 0.45rem;
  color: var(--fg-dim);
  font-size: 0.78rem;
  letter-spacing: 0.01em;
}

/* The opaque album id, demoted to a small monospace chip (tap to copy link). */
.id-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  max-width: 100%;
  padding: 0.2rem 0.55rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.75rem;
  color: var(--fg-dim);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.id-chip:hover {
  color: var(--label);
  border-color: var(--accent-bd);
}

.id-chip:active {
  background: var(--hover);
}


/* --- Image grid ------------------------------------------------------------ */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: 0.6rem;
  margin-top: 1rem;
}

.thumb {
  position: relative;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--tile);
  aspect-ratio: 5 / 4;
}

.thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.2s;
}

.thumb:hover img {
  transform: scale(1.04);
}

.thumb:active {
  border-color: var(--accent-bd);
}

.badge {
  position: absolute;
  bottom: 0.4rem;
  padding: 0.1rem 0.4rem;
  font-size: 0.7rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--fg-bright);
  background: rgba(20, 22, 26, 0.78);
  border-radius: 0.35rem;
  pointer-events: none;
}

.badge-format {
  left: 0.4rem;
  letter-spacing: 0.03em;
}

.badge-size {
  right: 0.4rem;
}

/* --- Lightbox -------------------------------------------------------------- */
.lightbox {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.9);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.25rem;
  cursor: zoom-out;
  z-index: 100;
}

.lightbox-img {
  max-width: 94vw;
  max-height: 82vh;
  object-fit: contain;
  border-radius: var(--radius-sm);
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.6);
}

.lightbox-actions {
  position: fixed;
  bottom: calc(1.25rem + env(safe-area-inset-bottom, 0px));
  left: 1.25rem;
  right: 1.25rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  pointer-events: none;
}

.lightbox-close {
  pointer-events: all;
  width: 44px;
  height: 44px;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(20, 22, 26, 0.75);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  color: var(--fg-bright);
  font-size: 1.1rem;
  backdrop-filter: blur(6px);
}

.lightbox-close:hover {
  background: rgba(30, 34, 40, 0.9);
  border-color: var(--danger);
  color: var(--danger);
}

.lightbox-download {
  pointer-events: all;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 44px;
  padding: 0 1.15rem;
  background: var(--accent-fill);
  color: var(--fg-bright);
  border: 1px solid var(--accent-bd);
  border-radius: var(--radius-sm);
  font-weight: 600;
  text-decoration: none;
  backdrop-filter: blur(6px);
}

.lightbox-download:hover {
  background: var(--accent-fill-hi);
}

a.download-all-bottom {
  margin-top: 1rem;
  display: none;
}

/* --- Settings / link pages -------------------------------------------------- */
.panel {
  margin-top: 1rem;
  padding: 1rem 1.1rem 1.1rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.panel h2 {
  margin: 0 0 0.75rem;
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--fg-dim);
}

.panel-hint {
  margin: 0 0 0.75rem;
  color: var(--fg-dim);
  font-size: 0.9rem;
}

.muted {
  color: var(--fg-dim);
}

.empty {
  padding: 2.5rem 0;
  color: var(--fg-dim);
}

.row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.55rem 0;
  border-top: 1px solid var(--border);
}

.row:first-of-type {
  border-top: none;
}

.row-label {
  flex: none;
  width: 10rem;
  color: var(--fg-dim);
  font-size: 0.9rem;
}

.row-value {
  color: var(--label);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.input {
  flex: 1;
  min-width: 0;
  height: 38px;
  padding: 0 0.7rem;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--fg);
  font: inherit;
}

.input:focus {
  outline: none;
  border-color: var(--accent-bd);
}

.input-code {
  width: 100%;
  height: 48px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 1.25rem;
  letter-spacing: 0.12em;
  text-align: center;
  text-transform: uppercase;
}

.actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
  margin-top: 0.9rem;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  flex: none;
  min-height: 40px;
  padding: 0 0.9rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong);
  background: transparent;
  color: var(--label);
  font: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}

.btn:hover:not(:disabled) {
  background: var(--hover);
  border-color: var(--fg-dim);
}

.btn:disabled {
  opacity: 0.55;
  cursor: default;
}

.btn-primary {
  border-color: var(--accent-bd);
  background: var(--accent-fill);
  color: var(--fg-bright);
}

.btn-primary:hover:not(:disabled) {
  background: var(--accent-fill-hi);
  border-color: var(--accent-bd);
}

.btn-danger {
  border-color: var(--border-strong);
  color: var(--danger);
}

.btn-danger:hover:not(:disabled) {
  border-color: var(--danger);
  background: rgba(224, 122, 122, 0.12);
  color: var(--danger);
}

@media (prefers-reduced-motion: reduce) {
  .btn {
    transition: none;
  }
}


.paired {
  margin: 0 0 0.4rem;
  color: var(--fg-bright);
  font-weight: 600;
}

/* The scanner being approved: the one thing on the consent screen the user has
   to read before deciding. */
.consent-name {
  margin: 0 0 0.5rem;
  color: var(--fg-bright);
  font-size: 1.15rem;
  font-weight: 600;
}

/* The same code the scanner is displaying, so the two can be compared at a
   glance. Matches the manual-entry field's type treatment. */
.consent-code {
  margin: 0 0 0.6rem;
  color: var(--fg);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 1.35rem;
  letter-spacing: 0.12em;
}

.topbar-link {
  color: var(--fg-dim);
  font-size: 0.85rem;
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 22ch;
}

.topbar-link:hover {
  color: var(--accent);
}

/* --- Paired scanners -------------------------------------------------------- */
.device-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.device {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.6rem 0;
  border-top: 1px solid var(--border);
}

.device:first-child {
  border-top: none;
}

.device-revoked {
  opacity: 0.5;
}

.device-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.device-name {
  color: var(--label);
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.device-sub {
  color: var(--fg-dim);
  font-size: 0.82rem;
}

.device-badge {
  flex: none;
  padding: 0.15rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--fg-dim);
  font-size: 0.75rem;
}

/* --- Mobile ---------------------------------------------------------------- */
/* --- Upload page ----------------------------------------------------------- */
a.btn {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
}

.album-title-input {
  width: 100%;
  margin: 0.85rem 0;
  padding: 0.5rem 0.7rem;
  font: inherit;
  color: var(--fg);
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
}

.album-title-input:disabled {
  opacity: 0.6;
}

.dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  position: relative;
  padding: 2rem 1rem;
  text-align: center;
  cursor: pointer;
  background: var(--surface-2);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
}

.dropzone.is-hovering {
  border-color: var(--accent-bd);
  background: var(--accent-fill);
}

/* Visually hidden, but still focusable from the keyboard: the whole zone is a
   <label>, so a click anywhere on it opens the picker. */
.dropzone-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.dropzone-input:focus-visible + .dropzone-text {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.dropzone-text {
  color: var(--fg-bright);
  font-weight: 600;
}

.dropzone-hint {
  color: var(--fg-dim);
  font-size: 0.85rem;
}

.resume-banner {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 0.85rem 0;
  padding: 0.7rem 0.9rem;
  color: var(--label);
  background: var(--surface);
  border: 1px solid var(--accent-bd);
  border-radius: var(--radius);
}

.resume-banner > span {
  flex: 1;
  min-width: 12rem;
}

.resume-hint {
  color: var(--fg-dim);
  font-size: 0.9rem;
}

.batch-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 0.9rem 0 0.5rem;
}

.batch-bar.is-hidden {
  display: none;
}

.batch-counts {
  flex: 1;
  min-width: 12rem;
  color: var(--fg-dim);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
}

.batch-failed {
  color: var(--danger);
  font-size: 0.9rem;
  font-weight: 600;
}

.batch-actions {
  display: flex;
  gap: 0.5rem;
}

.upload-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.upload-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto minmax(6rem, 10rem) 5.5rem;
  align-items: center;
  gap: 0.7rem;
  padding: 0.5rem 0.7rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.upload-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--fg-dim);
  transition: color 0.12s ease, border-color 0.12s ease, background 0.12s ease;
}

.upload-remove:hover:not(:disabled) {
  color: var(--danger);
  border-color: var(--danger);
  background: rgba(224, 122, 122, 0.12);
}

.upload-remove:disabled {
  opacity: 0.3;
  cursor: default;
}

.upload-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--fg);
  font-size: 0.9rem;
}

.upload-badge {
  padding: 0.1rem 0.4rem;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--fg-bright);
  background: var(--tile);
  border-radius: 0.35rem;
}

.upload-size {
  color: var(--fg-dim);
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
}

.upload-bar {
  height: 6px;
  overflow: hidden;
  background: var(--tile);
  border-radius: 3px;
}

.upload-bar-fill {
  height: 100%;
  background: var(--accent);
  border-radius: 3px;
  transition: width 0.15s linear;
}

.upload-state {
  text-align: right;
  color: var(--fg-dim);
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.upload-row.is-done .upload-bar-fill {
  background: #6fbf8f;
}

.upload-row.is-nopreview .upload-bar-fill {
  background: var(--fg-dim);
}

.upload-row.is-failed {
  border-color: var(--danger);
}

.upload-row.is-failed .upload-bar-fill,
.upload-row.is-cancelled .upload-bar-fill {
  background: var(--danger);
}

.upload-row.is-failed .upload-state {
  color: var(--danger);
}

.upload-row.is-cancelled {
  opacity: 0.6;
}

@media (prefers-reduced-motion: reduce) {
  .upload-bar-fill,
  .upload-remove {
    transition: none;
  }
}

@media (max-width: 640px) {
  .row {
    flex-direction: column;
    align-items: stretch;
    gap: 0.3rem;
  }

  .row-label {
    width: auto;
  }

  .actions {
    justify-content: stretch;
  }

  .actions .btn {
    flex: 1;
  }

  .container {
    margin-top: 0.5rem;
  }

  /* Edge to edge: the side margins cancel the container's horizontal inset.
     No negative top margin — the navbar lives inside this same container, so
     pulling upward would slide the banner over it. The topbar has no bottom
     margin, so zero already sits flush beneath it. The aspect ratio reserves
     the space before the video loads, so the album below does not jump. */
  .album-banner {
    display: block;
    margin: 0 -1rem 0.9rem;
    aspect-ratio: 640 / 200;
    overflow: hidden;
    background: var(--tile) center / cover no-repeat;
  }

  /* The whole banner is one link; the video must not swallow the tap. */
  .album-banner-video {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    pointer-events: none;
  }

  /* Stays a row on narrow screens: the title and its stats on the left, the
     actions on the right, sharing the block's full height. Stacking them
     instead pushed the grid a whole button below the fold for no gain. */
  .album-header {
    flex-direction: row;
    align-items: stretch;
    gap: 0.6rem;
  }

  .album-headtext {
    flex: 1;
    min-width: 0;
  }

  /* Actions stack against the text block and stretch to match its height. */
  .album-actions {
    flex: none;
    flex-direction: column;
    align-items: stretch;
    justify-content: stretch;
    flex-wrap: nowrap;
    gap: 0.4rem;
  }

  /* Stretch to the text block's height, but never below a usable target: two
     stacked buttons grow the header rather than squashing into slivers. */
  .album-actions .btn {
    flex: 1;
    width: auto;
    padding: 0 0.75rem;
  }

  /* Long titles must wrap rather than shove the buttons off-screen. */
  .album-header h1 {
    overflow-wrap: anywhere;
  }

  /* Confirming turns the column into a small stacked panel of its own. */
  .confirm-delete {
    text-align: right;
    font-size: 0.8rem;
  }

  /* Anchored under a narrow title, the panel would overflow the viewport. */
  .qr-pop {
    left: 50%;
    transform: translate(-50%, -4px);
  }

  .album-title-wrap:hover .qr-pop,
  .album-title-wrap:focus-within .qr-pop {
    transform: translate(-50%, 0);
  }

  .album-list {
    grid-template-columns: 1fr;
  }

  .grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 0.5rem;
  }

  a.download-all-bottom {
    display: flex;
    width: 100%;
    margin-top: 0.75rem;
  }
}

/* Narrow screens: the row loses its size and format columns, and the progress
   bar takes the width they leave behind. */
@media (max-width: 640px) {
  .upload-row {
    grid-template-columns: auto minmax(0, 1fr) 4.5rem;
  }

  .upload-badge,
  .upload-size {
    display: none;
  }

  .upload-bar {
    grid-column: 1 / -1;
  }

  .upload-remove {
    width: 30px;
    height: 30px;
  }

  .batch-actions {
    width: 100%;
  }

  .batch-actions > * {
    flex: 1;
  }
}

/* A looping video is exactly what someone asking for less motion does not want.
   Fall back to the poster frame — the banner still reads and still links. */
@media (max-width: 640px) and (prefers-reduced-motion: reduce) {
  .album-banner {
    background-image: url("/media/course-medium-format-darkroom.jpg");
  }

  .album-banner-video {
    display: none;
  }
}
