/* ============ Design tokens (shared with Workout + Inspiration Gallery) ============
 *
 * Same palette and geometry as the sibling apps — this is the house system,
 * not a per-app choice. Change a token here only if it's changing in all of them.
 */
:root {
  --teal:      #41b7ab;
  --teal-dark: #369a90; /* accessible teal for text-on-white */
  --slate:     #515a60;
  --bg:        #ffffff;
  --border:    #dddddd;
  --ink:       #222222;
  --black:     #000000;
  --teal-tint: #e8f6f4;
  --error:     #c05252;

  --surface:   #ffffff;
  --text:      var(--slate);
  --heading:   var(--slate);

  /* Book-tracker additions. The heart is deliberately NOT the teal: it sits on
     top of cover art of every possible colour and has to stay findable. */
  --heart:     #d4576b;
  --star:      #e0a72c;

  --radius: 10px;
  --tap: 48px;
  --maxw: 620px;
  --font: "Avenir Next", Avenir, "Segoe UI", system-ui, -apple-system, sans-serif;

  --safe-top:    env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);

  /* Pin to light so iOS doesn't auto-darken inputs and scrollbars for people
     whose phone is in dark mode. */
  color-scheme: light;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }

body {
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.5;
  color: var(--text);
  background: var(--bg);
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
}

button, input, textarea, select { font: inherit; }
button { cursor: pointer; }

[hidden] { display: none !important; }
.hidden { display: none !important; }
.muted { color: var(--slate); opacity: 0.7; font-weight: 400; }
.hint { font-size: 0.82rem; color: var(--slate); opacity: 0.75; }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ============ Layout ============ */

.wrap {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: calc(var(--safe-top) + 18px) 18px
           calc(var(--safe-bottom) + var(--tap) + 34px);
}

/* The public view has no tab bar, so it doesn't need the clearance for one.
   Embedded in an iframe, that extra 82px reads as a broken gap. */
.wrap-public { padding-bottom: calc(var(--safe-bottom) + 24px); }

.screen-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  border-bottom: 2px solid var(--teal);
  padding-bottom: 10px;
  margin: 4px 0 20px;
}
h1 { font-size: 1.7rem; font-weight: 500; margin: 0; color: var(--heading); letter-spacing: 0.2px; }
h2 { font-size: 1.1rem; font-weight: 600; margin: 26px 0 10px; color: var(--heading); }
.rule { border: 0; border-top: 2px solid var(--teal); margin: 28px 0 18px; }

.stack { display: grid; gap: 14px; }
.row { display: flex; align-items: center; gap: 10px; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: 10px; }

/* ============ Bottom tab bar ============ */

.tabbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  display: flex;
  background: var(--surface);
  border-top: 1px solid var(--border);
  padding-bottom: var(--safe-bottom);
  z-index: 20;
}
.tabbar a {
  flex: 1;
  min-height: var(--tap);
  display: flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  color: var(--slate);
  font-size: 0.9rem;
  font-weight: 600;
  border-top: 2px solid transparent;
  margin-top: -1px;
}
.tabbar a.is-active { color: var(--teal-dark); border-top-color: var(--teal); }

/* Add is an action, not a place, so it doesn't get equal width with the two
   tabs — and it's on the right, where a thumb reaches. */
.tabbar .tab-add {
  flex: 0 0 var(--tap);
  font-size: 1.6rem;
  font-weight: 400;
  color: var(--teal-dark);
  line-height: 1;
}

/* ============ Cover grid ============ */

/* auto-fill rather than a fixed count: three across on a phone, more on a
   tablet, without a media query per breakpoint. */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: 14px 12px;
  margin-bottom: 22px;
}

.card {
  display: flex;
  flex-direction: column;
  gap: 5px;
  text-decoration: none;
  color: inherit;
  /* The whole card is the tap target, and a cover is already well over 48px
     tall, so no min-height is needed here. */
}
.card:focus-visible { outline: 2px solid var(--teal); outline-offset: 3px; border-radius: var(--radius); }

.card-art {
  position: relative;
  display: block;
  aspect-ratio: 2 / 3;
  border-radius: 6px;
  overflow: hidden;
  background: var(--teal-tint);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
}
.cover { display: block; width: 100%; height: 100%; object-fit: cover; }

/* A book with no cover art is normal, not broken — Open Library doesn't have
   everything, and a cover that comes back too small to display is rejected
   rather than shown blurry. Both land here.
 *
 * Solid brand turquoise, carrying the title in white. An untitled grey box at
 * grid size is unidentifiable, and these are exactly the books most likely to
 * need attention.
 *
 * White on this turquoise measures ~2.4:1, below the WCAG AA bar — an owner
 * decision, made knowingly for the look. The type below claws back what it can
 * within that choice: larger and heavier than the card titles, with a soft
 * shadow to separate it from the background. Don't quietly "fix" this to dark
 * text; it was asked for. */
.cover-none {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px;
  background: var(--teal);
  color: #fff;
}
.cover-none span {
  /* Bigger and heavier than a card title, and shadowed — white on turquoise is
     low-contrast, so the type does the work the colours can't. */
  font-size: 0.82rem;
  font-weight: 700;
  line-height: 1.3;
  text-align: center;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
  /* Clamp rather than overflow: a long title must not push the box out of
     shape and break the grid rhythm. */
  display: -webkit-box;
  -webkit-line-clamp: 5;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.card-title {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.25;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.card-author {
  font-size: 0.74rem;
  color: var(--slate);
  opacity: 0.8;
  line-height: 1.2;
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Abandoned books stay in the grid, visually distinct rather than hidden. */
.card.is-abandoned .card-art { opacity: 0.62; }
.card.is-abandoned .card-title { font-style: italic; }

.badge {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 3px 5px;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-align: center;
  text-transform: uppercase;
  color: #fff;
  background: rgba(0, 0, 0, 0.62);
}

/* The favourite marker. A heart, never a star — the rating beside it is
   already five stars and a sixth is illegible at this size.
 *
 * Sitting inline is the DEFAULT, because that's what it does everywhere except
 * one place. Overlaying cover art is the special case, below. Doing it the
 * other way round means every context that isn't a card — the detail sheet, a
 * ratings row — has to override the positioning back off, and one that forgets
 * gets a heart absolutely positioned out of its container entirely. */
.fav {
  font-size: 1rem;
  line-height: 1;
  color: var(--heart);
}

/* Over cover art it pins to the corner, and needs the shadow to stay legible
   on a pale cover. */
.card-art .fav {
  position: absolute;
  top: 5px; right: 5px;
  text-shadow: 0 0 3px rgba(255, 255, 255, 0.95), 0 1px 2px rgba(0, 0, 0, 0.3);
}

/* Compact variant for the "Reading now" strip. */
.card.is-compact .card-title { font-size: 0.74rem; -webkit-line-clamp: 1; }
.card.is-compact .card-author { display: none; }

/* ============ Year dividers ============ */

/* The rule runs to the edges with the year sitting in it, so the year reads as
   a marker in the scroll rather than a heading for the block below. */
.year-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 26px 0 16px;
  color: var(--teal-dark);
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: 0.04em;
}
.year-divider::before,
.year-divider::after {
  content: "";
  flex: 1;
  border-top: 2px solid var(--teal);
}
.year-divider span { flex: 0 0 auto; }

/* ============ Reading now ============ */

/* Horizontally scrolling so an in-progress pile never pushes the collection
   below the fold. Private surface only. */
.reading-strip {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  padding-bottom: 6px;
  margin-bottom: 8px;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}
.reading-strip .card { flex: 0 0 84px; scroll-snap-align: start; }

/* ============ Stars, hearts, chips ============ */

.stars { white-space: nowrap; letter-spacing: 1px; }
.star { color: var(--border); }
.star.is-on { color: var(--star); }

.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  display: inline-block;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--teal-tint);
  color: var(--teal-dark);
  font-size: 0.76rem;
  font-weight: 600;
}

.meta { font-size: 0.84rem; color: var(--slate); opacity: 0.85; }

/* ============ Fields ============ */

.field { display: flex; flex-direction: column; gap: 6px; }
.field > span, .label { font-size: 0.95rem; font-weight: 400; color: var(--heading); }

input[type="text"], input[type="search"], input[type="date"],
input[type="number"], input[type="password"], textarea, select {
  width: 100%;
  min-height: var(--tap);
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  /* 16px minimum or iOS zooms the viewport on focus and never zooms back. */
  font-size: 16px;
}
textarea { min-height: 96px; resize: vertical; line-height: 1.45; }
input:focus, textarea:focus, select:focus {
  outline: 2px solid var(--teal);
  outline-offset: 1px;
  border-color: var(--teal);
}

/* ============ Buttons ============ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: var(--tap);
  padding: 0 18px;
  border: 1px solid var(--teal);
  border-radius: var(--radius);
  background: var(--teal);
  color: #fff;
  font-size: 1rem;
  font-weight: 600;
  text-decoration: none;
}
.btn-secondary { background: var(--surface); color: var(--teal-dark); }
.btn-danger { background: var(--surface); border-color: var(--error); color: var(--error); }
.btn-block { width: 100%; }
.btn:disabled { opacity: 0.5; }

/* Segmented control — status toggle, format picker, star rating input. */
.segmented { display: flex; gap: 0; border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.segmented label {
  flex: 1;
  min-height: var(--tap);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--slate);
  background: var(--surface);
  border-right: 1px solid var(--border);
}
.segmented label:last-child { border-right: 0; }
.segmented input { position: absolute; opacity: 0; pointer-events: none; }
.segmented input:checked + span,
.segmented label:has(input:checked) { background: var(--teal-tint); color: var(--teal-dark); }

/* ============ Search results (add flow) ============ */

.results { display: grid; gap: 0; margin-top: 14px; }
.result {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: var(--tap);
  padding: 10px 4px;
  border-bottom: 1px solid var(--border);
  text-decoration: none;
  color: inherit;
}
.result-art {
  flex: 0 0 42px;
  aspect-ratio: 2 / 3;
  border-radius: 4px;
  overflow: hidden;
  background: var(--teal-tint);
}
.result-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.result-text { min-width: 0; }
.result-title { font-weight: 600; color: var(--ink); font-size: 0.94rem; }
.result-author { font-size: 0.82rem; color: var(--slate); opacity: 0.85; }

/* Always last, always reachable, never waiting on the network. It's the escape
   hatch for books the API doesn't have. */
.result-new { color: var(--teal-dark); font-weight: 700; }

.searching { padding: 14px 4px; font-size: 0.88rem; color: var(--slate); opacity: 0.8; }

/* ============ Detail panel ============ */

.sheet {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  max-height: 88vh;
  overflow-y: auto;
  padding: 18px 18px calc(var(--safe-bottom) + 24px);
  background: var(--surface);
  border-radius: 16px 16px 0 0;
  box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.22);
  z-index: 40;
}
.sheet-backdrop {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.4);
  z-index: 39;
}
.sheet-head { display: flex; gap: 14px; margin-bottom: 14px; }
.sheet-art { flex: 0 0 92px; aspect-ratio: 2 / 3; border-radius: 6px; overflow: hidden; background: var(--teal-tint); }
.sheet-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sheet h2 { margin: 0 0 2px; font-size: 1.15rem; }
.sheet .notes { margin-top: 12px; white-space: pre-wrap; }

@media (prefers-reduced-motion: no-preference) {
  .sheet { animation: sheet-up 0.22s ease-out; }
  @keyframes sheet-up { from { transform: translateY(12%); opacity: 0.4; } to { transform: none; opacity: 1; } }
}

/* ============ Empty states ============ */

.empty {
  padding: 34px 18px;
  text-align: center;
  color: var(--slate);
  opacity: 0.8;
  font-size: 0.94rem;
}

/* ============ Desktop ============ */

/* Mobile-first: everything above is the phone layout. This is the only
   breakpoint, and it only widens the column and the grid. */
@media (min-width: 700px) {
  :root { --maxw: 880px; }
  .grid { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 18px 16px; }
  .sheet {
    left: 50%; right: auto; bottom: auto; top: 50%;
    width: min(560px, 92vw);
    transform: translate(-50%, -50%);
    border-radius: 14px;
    max-height: 86vh;
  }
}
