/* The shared book library ------------------------------------------------ */

/* Shelf summary */
.shelf-stats {
  display: grid; gap: .7rem; margin-bottom: 1.6rem;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
}

/* Toolbar: search takes the slack, the selects stay their natural width. */
.library-toolbar { align-items: flex-end; gap: .7rem .9rem; margin-bottom: 1.4rem; }
.field--search { flex: 1 1 220px; min-width: 180px; }
.field--inline { flex: 0 0 auto; }
.field--inline select { min-width: 8.5rem; }

/* --- the grid ---------------------------------------------------------- */

.book-grid {
  display: grid; gap: 1.1rem;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
}

.book {
  display: flex; flex-direction: column; gap: .65rem;
  background: var(--paper-raised); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: .8rem; cursor: pointer;
  transition: border-color .15s, transform .15s, box-shadow .15s;
}
.book:hover, .book:focus-visible {
  border-color: var(--green); transform: translateY(-2px);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .09);
}
.book:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }

/* A book cover is roughly 2:3. Reserving that box keeps the grid from
   reflowing as remote cover images arrive one by one. */
.book__cover {
  width: 100%; aspect-ratio: 2 / 3; object-fit: cover;
  border-radius: var(--r-sm); background: var(--paper-sunk);
  display: block;
}
/* A cover URL that 404s would otherwise leave a broken-image glyph. */
.book__cover.is-broken { visibility: hidden; }

.book__cover--blank {
  display: flex; align-items: center; justify-content: center;
  padding: .8rem; text-align: center; overflow: hidden;
  font-family: var(--font-display), Georgia, serif;
  font-size: .84rem; line-height: 1.3; font-weight: 600;
}
/* A long title is clamped by line rather than by character count, so it
   never breaks mid-word the way a JS substring would. */
.book__cover--blank span {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 6;
  overflow: hidden;
}

.book__body { display: flex; flex-direction: column; gap: .3rem; }
.book__title {
  font-size: .92rem; line-height: 1.3; margin: 0; font-weight: 600;
}
.book__author { font-size: .8rem; color: var(--ink-faint); margin: 0; }
.book__meta { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem; margin-top: .15rem; }

/* --- setting the status ------------------------------------------------- */

.status-set { display: inline-flex; flex-wrap: wrap; gap: .25rem; }
.status-set__btn {
  font: inherit; font-size: .75rem; line-height: 1; cursor: pointer;
  padding: .34rem .6rem; border-radius: 999px;
  border: 1px solid var(--line-strong); background: transparent; color: var(--ink-soft);
  transition: background .15s, color .15s, border-color .15s;
}
.status-set__btn:hover { background: var(--paper-sunk); color: var(--ink); }
.status-set__btn[aria-pressed="true"] {
  background: var(--green); color: #fff; border-color: var(--green); font-weight: 600;
}
/* Same inversion the filled .btn takes in dark mode, for the same reason:
   --green lightens there, so white text on it stops being legible. */
html[data-theme="dark"] .status-set__btn[aria-pressed="true"] { color: #0e1512; }
.status-set__btn:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

.lent-row { display: flex; gap: .4rem; align-items: center; margin: 0 0 .7rem; }
.lent-row input {
  flex: 1 1 auto; min-width: 0; font: inherit; font-size: .82rem;
  padding: .38rem .6rem; border-radius: var(--r-sm);
  border: 1px solid var(--line-strong); background: var(--paper-raised); color: var(--ink);
}
.lent-row input:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }

/* A back issue has no cover in any catalogue, so the placeholder gives it the
   one thing the shelf photo does show: the yellow border and the date. */
.book__cover--issue {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; gap: .1rem;
  background: #ffd200; border: 6px solid #ffd200; box-shadow: inset 0 0 0 3px #1a1a1a;
  color: #1a1a1a; padding: .6rem .5rem; overflow: hidden;
}
.issue__month {
  font-size: .62rem; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  line-height: 1.3; max-width: 100%;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
}
/* A special with no date on its spine has only this line, so it gets the room
   the year would have taken rather than sitting shrunken at the top. */
.book__cover--issue:not(:has(.issue__year)) .issue__month { font-size: .78rem; }
.issue__year { font-family: var(--font-display); font-size: 1.6rem; font-weight: 700; line-height: 1; }
/* The lead story is what actually tells two issues apart; it gets the room
   left over, clamped so a long one cannot push the year out of the frame. */
.issue__lead {
  margin-top: .3rem; font-size: .6rem; line-height: 1.3; font-weight: 600;
  border-top: 1px solid rgba(26, 26, 26, .35); padding-top: .3rem; max-width: 100%;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
}
.chip--issue { background: #ffd200; color: #1a1a1a; border-color: #e0b800; font-weight: 600; }

/* Three lines of the blurb, so a card stays a card. Clamped rather than
   truncated in JS: the full text is in the DOM for find-in-page, and the cut
   lands on a line rather than mid-word. */
.book__desc {
  font-size: .78rem; line-height: 1.45; color: var(--ink-faint); margin: .1rem 0 0;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
  overflow: hidden;
}

/* --- stars ------------------------------------------------------------- */

.stars { display: inline-flex; gap: .1rem; align-items: center; }
.stars .star { color: var(--line-strong); font-size: 1.05rem; line-height: 1; }
.stars .star[data-on="true"] { color: var(--gold); }
.stars--sm .star { font-size: .85rem; }

.stars--input .star {
  background: none; border: 0; padding: .1rem .05rem; cursor: pointer;
  font-size: 1.5rem;
}
.stars--input .star:focus-visible { outline: 2px solid var(--green); outline-offset: 1px; }

/* --- detail ------------------------------------------------------------ */

.detail-grid {
  display: grid; gap: 1.2rem;
  grid-template-columns: minmax(0, 150px) minmax(0, 1fr);
  align-items: start;
}
@media (max-width: 520px) {
  .detail-grid { grid-template-columns: 1fr; }
  .detail__cover { max-width: 180px; }
}
.detail__cover {
  width: 100%; aspect-ratio: 2 / 3; object-fit: cover;
  border-radius: var(--r-sm); background: var(--paper-sunk);
}
.detail__subtitle { font-size: 1rem; color: var(--ink-soft); margin: 0 0 .3rem; }
.detail__authors { margin: 0 0 .7rem; font-weight: 500; }
.detail__desc { margin-top: 1.1rem; line-height: 1.65; }
.detail__notes {
  margin-top: 1.1rem; padding: .8rem 1rem; border-radius: var(--r-sm);
  background: var(--paper-sunk); border: 1px solid var(--line);
}
.detail__notes p { margin: .3rem 0 0; white-space: pre-wrap; }

.kv-list { display: grid; gap: .3rem; margin: .9rem 0 0; }
.kv { display: flex; gap: .6rem; font-size: .86rem; }
.kv dt { color: var(--ink-faint); flex: 0 0 8.5rem; }
.kv dd { margin: 0; }

/* --- editor ------------------------------------------------------------ */

.modal--wide { max-width: 640px; }

.lookup__row { display: flex; gap: .5rem; align-items: stretch; }
.lookup__row input { flex: 1; }
.lookup__results { display: grid; gap: .5rem; margin-top: .7rem; }
.lookup__results:empty { margin-top: 0; }

.hit {
  display: flex; gap: .7rem; align-items: center;
  padding: .5rem .6rem; border: 1px solid var(--line);
  border-radius: var(--r-sm); background: var(--paper-sunk);
}
.hit__cover {
  width: 34px; height: 51px; object-fit: cover; flex: none;
  border-radius: 3px; background: var(--paper-raised);
}
.hit__body { display: flex; flex-direction: column; gap: .1rem; min-width: 0; flex: 1; }
.hit__body strong { font-size: .88rem; line-height: 1.25; }
.hit__body span { line-height: 1.3; }

.rule { border: 0; border-top: 1px solid var(--line); margin: 1.3rem 0; }

.cover-field { display: flex; gap: .9rem; align-items: flex-start; }
.cover-field__preview {
  width: 90px; aspect-ratio: 2 / 3; object-fit: cover;
  border-radius: var(--r-sm); border: 1px solid var(--line);
}
.cover-field__actions { display: flex; flex-direction: column; gap: .4rem; align-items: flex-start; }
.cover-field label.btn { cursor: pointer; }

/* Blank-spine tint ---------------------------------------------------------
   Stated last on purpose: `.detail__cover` also sets a background and carries
   the same specificity, so whichever comes later wins. The tint should. */
.book__cover--blank {
  background: hsl(var(--spine-hue, 120) 32% 88%);
  color: hsl(var(--spine-hue, 120) 45% 26%);
}
html[data-theme="dark"] .book__cover--blank {
  background: hsl(var(--spine-hue, 120) 22% 26%);
  color: hsl(var(--spine-hue, 120) 40% 84%);
}

/* Bulk gap-filling progress ----------------------------------------------- */

.bulk { margin: -.6rem 0 1.4rem; }
.bulk__track {
  height: 5px; border-radius: 999px; background: var(--paper-sunk);
  overflow: hidden; border: 1px solid var(--line);
}
.bulk__bar {
  height: 100%; width: 0; background: var(--green);
  transition: width .25s ease;
}
.bulk p { margin: .4rem 0 0; }

/* A filter button that stays lit while its filter is on. */
.btn.toggle[aria-pressed="true"] {
  background: var(--green); color: #fff; border-color: var(--green);
}
