/* ============================================================
   Practice — shared catalog styles (books / apps / tools / partners)
   Aesthetic matches the rest of the zen/red Practice design system.
   ============================================================ */

.catalog-page {
  width: min(1240px, 100% - 80px);
  margin: 120px auto 96px;
  position: relative;
  z-index: 1;
}
@media (max-width: 820px) {
  .catalog-page {
    width: min(1240px, 100% - 32px);
    margin: 90px auto 64px;
  }
}

/* ---------- Header ---------- */
.catalog-header {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px 40px;
  margin-bottom: 8px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--ink-line);
}
.catalog-header .eyebrow {
  font-family: var(--f-mono);
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--red);
  display: block;
  margin-bottom: 10px;
}
.catalog-header h1 {
  margin: 0;
  font-family: var(--f-serif);
  font-size: clamp(40px, 6vw, 72px);
  font-weight: 300;
  letter-spacing: 0.04em;
  line-height: 1.05;
}
.catalog-header h1 em {
  font-style: italic;
  color: var(--red);
}
.catalog-header .result-count {
  margin: 0;
  font-family: var(--f-mono);
  font-size: 11px;
  color: var(--ink-faint);
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

/* ---------- Controls ---------- */
.controls {
  display: grid;
  grid-template-columns: 1fr 240px;
  gap: 32px;
  margin: 40px 0 48px;
}
.field {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.field span {
  font-family: var(--f-mono);
  font-size: 10px;
  color: var(--red);
  letter-spacing: 0.3em;
  text-transform: uppercase;
}
@media (max-width: 820px) {
  .controls { grid-template-columns: 1fr; gap: 20px; }
}

/* ---------- Grid + card ---------- */
.catalog-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 48px 24px;
}

/* Historical: catalog.js may emit `.book-card` or `.catalog-card` depending
   on legacy pages. Style both identically. */
.book-card,
.catalog-card {
  border: 0;
  background: transparent;
  display: flex;
  flex-direction: column;
  gap: 14px;
  cursor: pointer;
  text-align: left;
  padding: 0;
  color: inherit;
  font-family: var(--f-serif);
  transition: transform 400ms var(--ease-zen);
  outline: none;
}
.book-card:focus-visible,
.catalog-card:focus-visible { outline: none; }

/* Bookmark star — top-right corner of each card's thumb-shell. Hidden
   until hovered/focused unless already saved (in which case it stays
   visible to indicate state). */
.card-bookmark {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  background: rgba(0, 0, 0, 0.55);
  border: 0;
  border-radius: 50%;
  color: var(--ink);
  cursor: pointer;
  opacity: 0;
  transform: translateY(-2px) scale(0.92);
  transition: opacity 200ms ease, transform 200ms var(--ease-zen),
              background 200ms ease, color 200ms ease;
  z-index: 2;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.book-card:hover .card-bookmark,
.book-card:focus-within .card-bookmark,
.catalog-card:hover .card-bookmark,
.catalog-card:focus-within .card-bookmark,
.card-bookmark:focus-visible,
.card-bookmark.is-saved {
  opacity: 1;
  transform: translateY(0) scale(1);
}
.card-bookmark i,
.card-bookmark svg {
  width: 16px;
  height: 16px;
  display: block;
  stroke: currentColor;
}
.card-bookmark.is-saved {
  color: var(--red);
  background: rgba(178, 34, 34, 0.18);
}
.card-bookmark.is-saved svg {
  fill: var(--red);
}
.card-bookmark:hover {
  background: rgba(0, 0, 0, 0.78);
}
.card-bookmark.is-saved:hover {
  background: rgba(178, 34, 34, 0.32);
}

/* Touch devices: always show the star since hover doesn't apply. */
@media (pointer: coarse) {
  .card-bookmark { opacity: 1; transform: none; }
}

.thumb-shell {
  overflow: hidden;
  background: var(--bg-raised);
  border: 0;
  border-radius: 14px;
  position: relative;
}
/* Hover dot intentionally removed — the bookmark star occupies the
   same top-right corner now and the two were stacking. */
.thumb-shell::after {
  content: none;
  display: none;
  opacity: 0;
  transform: scale(0.6);
  transition: opacity 300ms ease, transform 300ms var(--ease-zen);
}
/* (Hover ::after rule removed — see note above .thumb-shell::after.) */

.book-thumb,
.catalog-thumb {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  background: var(--bg-raised);
  display: block;
  border-radius: 14px;
  transform: scale(1);
  transition: transform 500ms var(--ease-zen), filter 400ms ease;
  filter: grayscale(0.3) contrast(1.02);
}

/* Movie posters use the standard 2:3 portrait ratio. Scoped to the
   Auditorium grid so games / apps / tools / books keep their squares. */
#auditoriumGrid .catalog-thumb,
#auditoriumGrid .book-thumb {
  aspect-ratio: 2 / 3;
}
#auditoriumGrid {
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
}

/* App icons are logos, not photographs — center them with padding so the
   shape isn't cropped. Tools and music already use the same logo-style
   thumbs and should match. The thumb-shell border is dropped on these
   grids so the logos sit cleanly on the page background. */
#appsGrid .catalog-thumb,
#toolsGrid .catalog-thumb,
#musicGrid .catalog-thumb {
  object-fit: contain;
  padding: 14%;
  filter: none;
  background: transparent;
  border-radius: 18px;
}
#appsGrid .thumb-shell,
#toolsGrid .thumb-shell,
#musicGrid .thumb-shell {
  border: 0;
  background: transparent;
  border-radius: 18px;
}
#appsGrid .catalog-card:hover .catalog-thumb,
#toolsGrid .catalog-card:hover .catalog-thumb,
#musicGrid .catalog-card:hover .catalog-thumb {
  transform: scale(1.06);
  filter: none;
}
.book-thumb.is-broken,
.catalog-thumb.is-broken {
  /* Graceful fallback for missing cover art: a quiet dashed square. */
  background: repeating-linear-gradient(45deg, var(--bg-raised) 0 10px, var(--bg) 10px 20px);
  filter: grayscale(1);
}

.book-title,
.catalog-title {
  margin: 0;
  font-family: var(--f-serif);
  font-size: 15px;
  font-weight: 300;
  line-height: 1.4;
  letter-spacing: 0.02em;
  color: var(--ink-soft);
  transition: color 300ms ease;
  text-wrap: pretty;
}

.book-card:hover .book-thumb,
.book-card:focus-visible .book-thumb,
.catalog-card:hover .catalog-thumb,
.catalog-card:focus-visible .catalog-thumb {
  transform: scale(1.04);
  filter: grayscale(0) contrast(1);
}
.book-card:hover .book-title,
.book-card:focus-visible .book-title,
.catalog-card:hover .catalog-title,
.catalog-card:focus-visible .catalog-title {
  color: var(--ink);
}
.book-card:focus-visible,
.catalog-card:focus-visible { outline: none; }
.book-card:focus-visible .thumb-shell,
.catalog-card:focus-visible .thumb-shell {
  border-color: var(--red);
}

/* ---------- Bookmarks page sections ---------- */
.bookmarks-section { margin-bottom: 56px; }
.bookmarks-section:last-child { margin-bottom: 24px; }
.bookmarks-section-head {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin-bottom: 22px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--ink-line);
}
.bookmarks-section-title {
  font-family: var(--f-serif);
  font-weight: 300;
  font-size: 24px;
  letter-spacing: 0.005em;
  color: var(--ink);
  margin: 0;
}
.bookmarks-section-count {
  font-family: var(--f-mono);
  font-size: 10px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-left: auto;
}

/* ---------- Recently played strip ----------
   Pinned row above the main grid that shows the last few items the user
   opened. Scrolls horizontally on narrow viewports so it never pushes
   the grid down. Hidden until something has been played. */
.recents-row {
  margin-bottom: 56px;
  padding-bottom: 36px;
  border-bottom: 1px solid var(--ink-line);
}
.recents-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 22px;
  gap: 16px;
}
.recents-title {
  font-family: var(--f-serif);
  font-weight: 300;
  font-size: 22px;
  letter-spacing: 0.005em;
  color: var(--ink);
  margin: 0;
}
.recents-clear {
  background: transparent;
  border: 0;
  color: var(--ink-faint);
  font-family: var(--f-mono);
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: lowercase;
  cursor: pointer;
  padding: 4px 0;
}
.recents-clear:hover { color: var(--red); }
.recents-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 32px 18px;
}
@media (max-width: 540px) {
  .recents-grid {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    padding-bottom: 8px;
  }
  .recents-card {
    flex: 0 0 110px;
    scroll-snap-align: start;
  }
}

/* ---------- Skeleton loaders ----------
   Pulsing placeholder cards rendered while the catalog JSON is in
   flight. They sit in the same grid as real cards so the layout
   doesn't jump on swap. .is-leaving fades them out; the JS removes
   the nodes after the transition completes. */
.skeleton-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 0;
  opacity: 1;
  transition: opacity 360ms ease;
}
.skeleton-card.is-leaving { opacity: 0; }
.skeleton-shell {
  width: 100%;
  aspect-ratio: 1 / 1;
  background: linear-gradient(
    100deg,
    rgba(236, 231, 220, 0.04) 0%,
    rgba(236, 231, 220, 0.10) 40%,
    rgba(236, 231, 220, 0.04) 80%
  );
  background-size: 240% 100%;
  animation: skeleton-shimmer 1.6s ease-in-out infinite;
  border: 0;
  border-radius: 14px;
}
.skeleton-title {
  height: 12px;
  width: 70%;
  background: linear-gradient(
    100deg,
    rgba(236, 231, 220, 0.04) 0%,
    rgba(236, 231, 220, 0.10) 40%,
    rgba(236, 231, 220, 0.04) 80%
  );
  background-size: 240% 100%;
  animation: skeleton-shimmer 1.6s ease-in-out infinite;
}
@keyframes skeleton-shimmer {
  0%   { background-position: 240% 0; }
  100% { background-position: -40% 0; }
}
/* Auditorium grid uses 2:3 portrait — match the skeleton ratio so the
   placeholder doesn't pop into a different shape on swap. */
#auditoriumGrid .skeleton-shell { aspect-ratio: 2 / 3; }
/* Apps / tools / music skeletons are logos — no border, slight rounding
   to match their real-card style. */
#appsGrid  .skeleton-shell,
#toolsGrid .skeleton-shell,
#musicGrid .skeleton-shell {
  border: 0;
  border-radius: 18px;
}
/* Lite mode: still shows skeletons but skips the shimmer animation. */
html.lite .skeleton-shell,
html.lite .skeleton-title { animation: none; opacity: 0.6; }

/* ---------- Empty / loading / load-more ---------- */
.empty-state {
  grid-column: 1 / -1;
  border: 1px dashed var(--ink-line);
  padding: 64px 28px;
  text-align: center;
  color: var(--ink-faint);
  font-family: var(--f-serif);
  font-style: italic;
  font-size: 15px;
  letter-spacing: 0.1em;
}

.render-status {
  margin: 40px 0 0;
  color: var(--ink-faint);
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  text-align: center;
}

.load-more-wrap {
  display: flex;
  justify-content: center;
  margin-top: 28px;
}
.load-more-btn {
  height: 44px;
  min-width: 200px;
  padding: 0 32px;
  border: 1px solid var(--ink-line);
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  transition: color 300ms ease, border-color 300ms ease, letter-spacing 300ms var(--ease-zen);
}
.load-more-btn:hover {
  color: var(--ink);
  border-color: var(--red);
  letter-spacing: 0.36em;
}
.load-more-btn:disabled {
  opacity: 0.35;
  cursor: default;
  letter-spacing: 0.3em;
}
.load-more-btn:disabled:hover {
  color: var(--ink-soft);
  border-color: var(--ink-line);
}

/* ============================================================
   Viewer modal
   ============================================================ */
.viewer {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.92);
  backdrop-filter: blur(8px);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 50;
  padding: 24px;
  opacity: 0;
  transition: opacity 300ms ease;
}
.viewer.is-open { display: flex; opacity: 1; }

.viewer-shell {
  width: min(1280px, 100%);
  height: min(88vh, 900px);
  border: 1px solid var(--ink-line);
  background: var(--bg);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  position: relative;
}
.viewer-shell::before {
  content: "";
  position: absolute;
  top: 18px;
  left: 18px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--red);
  box-shadow: 0 0 10px var(--red-glow);
  z-index: 2;
}

.viewer-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 20px;
  padding: 16px 20px 16px 40px;
  border-bottom: 1px solid var(--ink-line);
  flex-wrap: wrap;
}
.viewer-top h2 {
  margin: 0;
  font-family: var(--f-serif);
  font-size: 14px;
  font-weight: 300;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--ink);
  text-wrap: balance;
}
.viewer-actions { display: flex; gap: 4px; flex-wrap: wrap; align-items: center; }
.viewer-actions button {
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  border: 1px solid transparent;
  background: transparent;
  color: var(--ink-soft);
  padding: 0;
  cursor: pointer;
  border-radius: 4px;
  transition: color 200ms ease, border-color 200ms ease, background 200ms ease;
}
.viewer-actions button i {
  width: 16px;
  height: 16px;
  display: block;
}
.viewer-actions button svg { display: block; }
.viewer-actions button:hover {
  color: var(--ink);
  border-color: var(--ink-line);
  background: rgba(236, 231, 220, 0.04);
}
.viewer-actions button.viewer-close:hover {
  color: var(--red);
  border-color: var(--red);
  background: rgba(178, 34, 34, 0.08);
}

.viewer-frame {
  width: 100%;
  height: 100%;
  border: 0;
  background: #000;
  flex: 1;
}

@media (max-width: 820px) {
  .viewer-shell { height: min(92vh, 900px); }
  .viewer-top {
    flex-direction: column;
    align-items: flex-start;
    padding: 14px 16px 14px 36px;
  }
  .viewer-actions { width: 100%; justify-content: flex-start; }
}
