/* === BUTTONS === */
.btn {
  height: var(--control-height);
  padding: 0 20px;
  border: none;
  border-radius: var(--radius-md);
  font-size: 14px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease, opacity 0.15s ease;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  outline: none;
  position: relative;
  overflow: hidden;
  text-decoration: none;
}

.btn:focus-visible {
  box-shadow: var(--focus-ring);
}

.btn-primary {
  background: var(--accent);
  color: var(--on-accent);
}

.btn-primary:hover {
  background: var(--accent-hover);
}

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

.btn-secondary:hover {
  background: var(--bg-3);
  border-color: var(--border-hover);
}

.btn-danger {
  background: var(--danger);
  color: white;
}

.btn-danger:hover {
  background: #dc2626;
}

.btn-sm {
  height: 32px;
  padding: 0 14px;
  font-size: 13px;
  border-radius: var(--radius-sm);
}

.btn-icon {
  padding: 8px;
  border-radius: var(--radius-sm);
}

.btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* === MEDIA CARD === */
.media-card {
  aspect-ratio: 3/4;
  border-radius: 10px;
  overflow: hidden;
  position: relative;
  background: var(--bg-2);
  cursor: pointer;
  transition: opacity 0.3s ease, transform 0.3s ease;
  outline: none;
  animation: cardIn 0.5s cubic-bezier(0.4, 0, 0.2, 1) forwards;
  opacity: 0;
  transform: translateY(16px);
  /* content-visibility: auto lets the browser skip layout + paint for
     off-screen cards. Combined with contain-intrinsic-size it "reserves"
     the card's slot in the grid, so the scrollbar stays stable and the
     browser can jump to any position without laying out thousands of
     cards. Big win once the grid exceeds ~500 items on mobile. */
  content-visibility: auto;
  contain-intrinsic-size: 260px 340px;
}

.media-card:focus-visible {
  box-shadow: 0 0 0 2px var(--bg-0), 0 0 0 4px var(--accent);
}

.media-card img,
.media-card video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: filter 0.2s ease;
}

/* Без подпрыгивания и свечения: на hover фото чуть светлеет. */
@media (hover: hover) {
  .media-card:hover img {
    filter: brightness(1.08);
  }
}

.media-card.skeleton::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(110deg, var(--bg-2) 30%, var(--bg-3) 50%, var(--bg-2) 70%);
  background-size: 200% 100%;
  animation: skeleton-shimmer 1.4s ease-in-out infinite;
  z-index: 0;
}

.media-card.skeleton img {
  opacity: 0;
}

.media-card img {
  position: relative;
  z-index: 1;
}

@keyframes skeleton-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

.card-age {
  position: absolute;
  top: var(--space-2);
  left: var(--space-2);
  background: rgba(0, 0, 0, 0.55);
  padding: 2px 7px;
  border-radius: var(--radius-sm);
  font-size: 12px;
  font-weight: 500;
  line-height: 18px;
  color: white;
  pointer-events: none;
  z-index: 2;
}

.card-favorite {
  position: absolute;
  top: var(--space-1);
  right: var(--space-1);
  width: 36px;
  height: 36px;
  background: var(--overlay-scrim);
  backdrop-filter: blur(8px);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--overlay-hairline);
  cursor: pointer;
  transition: opacity 0.2s ease, transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
  z-index: 2;
  /* Сердечко не висит на каждой карточке: кнопка появляется по hover /
     клавиатурному фокусу, а у медиа в избранном остаётся только маркер. */
  opacity: 0;
  transform: scale(0.85);
}

.card-favorite svg {
  color: white;
  transition: color 0.2s ease, fill 0.2s ease;
}

/* Маркер «в избранном»: залитое сердце без подложки. */
.card-favorite.active {
  opacity: 1;
  transform: scale(1);
  background: transparent;
  border-color: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

.card-favorite.active svg {
  color: var(--danger);
  fill: var(--danger);
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.6));
}

/* На /favorites маркер был бы у всех карточек — прячем до hover. */
.is-favorites-page .card-favorite.active {
  opacity: 0;
}

.media-card:focus-visible .card-favorite,
.card-favorite:focus-visible {
  opacity: 1;
  transform: scale(1);
}

@media (hover: hover) {
  .media-card:hover .card-favorite {
    opacity: 1;
    transform: scale(1);
  }
  .media-card:hover .card-favorite.active {
    background: var(--overlay-scrim);
    border-color: var(--overlay-hairline);
  }
  .card-favorite:hover {
    background: var(--overlay-scrim-strong);
    transform: scale(1.1);
  }
}

/* Тач: кнопки на карточке нет — избранное переключается long-press'ом
   (см. setupLongPressFavorite), а маркер не перехватывает тап. */
@media (hover: none) {
  .card-favorite {
    pointer-events: none;
  }
  .media-card img {
    -webkit-touch-callout: none;
  }
  .media-card {
    -webkit-user-select: none;
    user-select: none;
  }
}

/* Анимация сердца по центру карточки после long-press. */
.card-fav-burst {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 3;
  color: white;
  pointer-events: none;
  filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.5));
  animation: favBurst 0.7s cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
}
.card-fav-burst.adding {
  color: var(--danger);
}
@keyframes favBurst {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.4); }
  30%  { opacity: 1; transform: translate(-50%, -50%) scale(1.1); }
  60%  { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .card-fav-burst {
    animation-duration: 0.5s;
    animation-timing-function: linear;
  }
}

.card-play {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 56px;
  height: 56px;
  background: rgba(255,255,255,0.15);
  backdrop-filter: blur(8px);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(255,255,255,0.2);
  cursor: pointer;
  transition: var(--transition);
  z-index: 2;
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.8);
}

.media-card:hover .card-play {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

.card-play:hover {
  background: rgba(255,255,255,0.25);
  transform: translate(-50%, -50%) scale(1.15);
}

.card-play svg {
  color: white;
}

/* Маленький постоянный маркер видео в нижнем левом углу. На hover его
   заменяет большая .card-play по центру. */
.card-video-badge {
  position: absolute;
  left: var(--space-2);
  bottom: var(--space-2);
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--overlay-scrim);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid var(--overlay-hairline);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
  pointer-events: none;
  transition: opacity 0.2s ease;
}
.card-video-badge svg {
  margin-left: 1px; /* оптически центрируем треугольник */
}
@media (hover: hover) {
  .media-card:hover .card-video-badge {
    opacity: 0;
  }
}

/* Animated WebP preview shown on hover over video cards. Absolute-position
   over the static thumbnail; fade in via opacity to avoid a jarring
   pop-in when the preview finishes loading. */
.card-preview {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 1;
  pointer-events: none;
  transition: opacity 150ms ease-out;
}

/* === LOADING === */
.loading-spinner {
  display: flex;
  justify-content: center;
  padding: 40px;
}

.spinner {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 3px solid var(--border);
  border-top-color: var(--accent);
  animation: spin 0.8s linear infinite;
}

/* === MODAL === */
.modal {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2000;
  opacity: 0;
  transition: opacity 0.3s;
}

.modal.active {
  display: block;
  opacity: 1;
  /* transition не срабатывает при переходе из display: none — анимируем
     появление через keyframes. */
  animation: fadeIn 0.2s ease-out;
}

.modal-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: var(--bg-0);
}

.modal-media-full {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal-media-full img,
.modal-media-full video {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.modal-media-full img {
  cursor: zoom-in;
}

/* Loading skeleton for modal: shows a tiny blur-up thumbnail + spinner
   until the full image is decoded, then fades the image in. The wrapper
   holds the absolute-positioned blur, the centered spinner, and the
   actual <img>/<video>. */
.modal-media-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  /* Smooth animation when the swipe-down gesture either snaps back to
     identity or animates the wrapper off-screen on commit. The JS sets
     transition: 'none' during the drag for 1:1 finger tracking. */
  transition: transform 0.25s ease, opacity 0.25s ease;
}
@media (prefers-reduced-motion: reduce) {
  .modal-media-wrapper {
    transition: none;
  }
}
.modal-media-blur {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  filter: blur(20px);
  transform: scale(1.1); /* hide the blur edge */
  z-index: 0;
}
.modal-media-spinner {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
  pointer-events: none;
}
.modal-media-spinner .spinner {
  width: 36px;
  height: 36px;
  border: 3px solid rgba(255,255,255,0.2);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
/* Image starts at opacity 0 to prevent the half-decoded frame from flashing.
   The wrapper itself gets .modal-media-ready once the image's load event
   fires - that triggers the image fade-in AND the simultaneous spinner
   and blur fade-out, all at the same time. */
.modal-media-loading {
  opacity: 0;
}
.modal-media-ready {
  opacity: 1;
  transition: opacity 0.35s ease;
}
/* When the wrapper is in the "ready" state, fade spinner and blur out
   together with the image so the loading indicators don't linger after
   the photo is on screen. */
.modal-media-wrapper.modal-media-ready .modal-media-spinner {
  opacity: 0;
  transition: opacity 0.2s ease;
}
.modal-media-wrapper.modal-media-ready .modal-media-blur {
  opacity: 0;
  transition: opacity 0.25s ease;
}
/* Inside the wrapper, the image sits above the blur but below the spinner. */
.modal-media-wrapper .modal-media {
  position: relative;
  z-index: 1;
}


.modal-close {
  position: absolute;
  top: var(--space-5);
  right: var(--space-5);
  width: 48px;
  height: 48px;
  background: var(--overlay-scrim);
  backdrop-filter: blur(10px);
  border: 1px solid var(--overlay-hairline);
  border-radius: 50%;
  color: white;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: var(--transition);
  z-index: 10;
  padding: 0;
}

.modal-close:hover {
  background: var(--overlay-scrim-strong);
  transform: rotate(90deg);
}

.modal-close svg {
  width: 24px;
  height: 24px;
}

.modal-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 56px;
  height: 56px;
  background: var(--overlay-scrim);
  backdrop-filter: blur(10px);
  border: 1px solid var(--overlay-hairline);
  border-radius: 50%;
  color: white;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: var(--transition);
  z-index: 10;
  padding: 0;
  opacity: 0;
}

.modal.active .modal-nav {
  opacity: 1;
}

.modal-nav:hover {
  background: var(--overlay-scrim-strong);
  transform: translateY(-50%) scale(1.1);
}

.modal-nav svg {
  width: 24px;
  height: 24px;
}

.modal-prev {
  left: 20px;
}

.modal-next {
  right: 20px;
}

.modal-bottom-bar {
  position: absolute;
  bottom: 32px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 10px var(--space-5);
  background: var(--overlay-scrim);
  backdrop-filter: blur(10px);
  border: 1px solid var(--overlay-hairline);
  border-radius: var(--radius-xl);
}

.modal-age {
  background: rgba(255,255,255,0.1);
  padding: 6px 14px;
  border-radius: 20px;
  font-size: 13px;
  font-weight: 600;
  color: white;
  border: 1px solid rgba(255,255,255,0.15);
}

.modal-favorite {
  width: 40px;
  height: 40px;
  background: rgba(255,255,255,0.1);
  border: 1px solid rgba(255,255,255,0.15);
  border-radius: 50%;
  color: white;
  cursor: pointer;
  transition: var(--transition);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}

.modal-favorite:hover {
  background: rgba(239, 68, 68, 0.3);
  border-color: rgba(239, 68, 68, 0.5);
  transform: scale(1.1);
}

.modal-favorite.active {
  background: rgba(239, 68, 68, 0.4);
  border-color: rgba(239, 68, 68, 0.6);
}

.modal-favorite.active svg {
  color: var(--danger);
  fill: var(--danger);
}

.modal-favorite svg {
  width: 20px;
  height: 20px;
}

/* === MODAL: AUTO-HIDE UI ===
   transform/background тоже в списке — иначе hover-поворот ✕ и
   увеличение стрелок происходили рывком. */
.modal-close,
.modal-edit,
.modal-nav,
.modal-bottom-bar {
  transition: opacity 0.3s ease, transform 0.25s ease, background 0.2s ease;
}

.modal.idle .modal-close,
.modal.idle .modal-edit,
.modal.idle .modal-nav,
.modal.idle .modal-bottom-bar,
.modal.idle .modal-add-collection {
  opacity: 0;
  pointer-events: none;
}

/* Мобилка. Родные <video>-контролы занимают снизу ~48px — при bottom:20px
   плашка с возрастом/сердцем ложится прямо на ползунок перемотки. Правило
   должно жить именно в components.css: любая @media в layout.css с тем же
   селектором проиграет каскаду, потому что components.css грузится после. */
@media (max-width: 600px) {
  .modal-bottom-bar {
    bottom: 32px;
    padding: 8px 14px;
  }
}

/* === MODAL EDIT BUTTON === */
.modal-edit {
  position: absolute;
  top: var(--space-5);
  left: var(--space-5);
  width: 48px;
  height: 48px;
  background: var(--overlay-scrim);
  backdrop-filter: blur(10px);
  border: 1px solid var(--overlay-hairline);
  border-radius: 50%;
  color: white;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: var(--transition);
  z-index: 10;
  padding: 0;
}

.modal-edit:hover {
  background: var(--overlay-scrim-strong);
  transform: scale(1.08);
}

.modal-edit svg {
  width: 22px;
  height: 22px;
}

/* === MODAL EDIT PANEL === */
.modal-edit-panel {
  position: absolute;
  inset: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(5, 5, 7, 0.6);
  backdrop-filter: blur(6px);
  animation: fadeIn 0.2s ease;
}

.modal-edit-panel[hidden] {
  display: none;
}

.edit-panel-content {
  width: 100%;
  max-width: 380px;
  max-height: calc(100vh - 48px);
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg), 0 0 0 1px rgba(255,255,255,0.04);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  animation: panelIn 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

@keyframes panelIn {
  from { opacity: 0; transform: translateY(8px) scale(0.97); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

.edit-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
}

.edit-panel-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
}

.edit-panel-close {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  color: var(--text-secondary);
  cursor: pointer;
  border-radius: 8px;
  transition: var(--transition);
  padding: 0;
}

.edit-panel-close:hover {
  background: var(--bg-2);
  color: var(--text-primary);
}

.edit-panel-body {
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  overflow-y: auto;
}

.edit-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.edit-field-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.edit-field-select {
  width: 100%;
  padding: 10px 12px;
  background: var(--bg-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text-primary);
  font-size: 14px;
  font-family: inherit;
  cursor: pointer;
  transition: var(--transition);
}

.edit-field-select:focus {
  outline: none;
  border-color: var(--primary);
  background: var(--bg-2);
}

.edit-panel-footer {
  display: flex;
  gap: 8px;
  justify-content: space-between;
  align-items: center;
  padding: 14px 20px;
  border-top: 1px solid var(--border);
  background: var(--bg-3);
}

.edit-panel-footer-right {
  display: flex;
  gap: 8px;
}

.edit-panel-footer .btn {
  min-width: 90px;
}

.btn-delete-media {
  min-width: 0;
  padding: 0 14px;
}

.btn-delete-media svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  stroke-width: 2.25;
}

/* На узких экранах кнопки в футере не помещаются с фиксированным min-width
   и Сохранить упирается в правую стенку. Раздаём ширину поровну через
   flex: 1, режем внутренний padding и уменьшаем padding самого футера,
   чтобы текст никогда не касался краёв. */
@media (max-width: 480px) {
  .edit-panel-footer {
    padding: 12px 14px;
    gap: 10px;
  }
  .edit-panel-footer .btn {
    min-width: 0;
    padding: 0 12px;
    flex: 1 1 0;
  }
  .edit-panel-footer-right {
    flex: 2 1 0;
    gap: 10px;
  }
  .btn-delete-media {
    padding: 0 12px;
  }
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* === EMPTY STATE === */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 80px 24px;
  text-align: center;
}

.empty-state-icon {
  font-size: 48px;
  margin-bottom: 16px;
  opacity: 0.3;
}

.empty-state-title {
  font-size: 18px;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 8px;
}

.empty-state-text {
  font-size: 14px;
  color: var(--text-muted);
  max-width: 400px;
}

/* === TOAST === */
.toast-container {
  position: fixed;
  top: 80px;
  right: 24px;
  z-index: 3000;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
}

.toast {
  padding: 14px 20px;
  border-radius: var(--radius-md);
  background: var(--bg-3);
  color: var(--text-primary);
  font-size: 14px;
  box-shadow: var(--shadow-lg);
  animation: toastIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  border: 1px solid var(--border);
  max-width: 320px;
  pointer-events: auto;
  backdrop-filter: blur(10px);
  display: flex;
  align-items: center;
  gap: 10px;
  transition: opacity 0.3s;
}

/* Common ::before badge — a colored dot with a matching glow. Icon-like
   without pulling in an SVG per toast type. */
.toast::before {
  content: '';
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}
.toast .toast-text {
  flex: 1;
  min-width: 0;
}
.toast .toast-close {
  background: transparent;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  font-size: 20px;
  line-height: 1;
  padding: 0 4px;
  transition: color 0.2s;
}
.toast .toast-close:hover {
  color: var(--text-primary);
}

.toast.success { border-color: rgba(34, 197, 94, 0.3); }
.toast.success::before { background: var(--success); }

.toast.error { border-color: rgba(239, 68, 68, 0.3); }
.toast.error::before { background: var(--danger); }

.toast.info { border-color: rgba(59, 130, 246, 0.3); }
.toast.info::before { background: var(--info); }

.toast.warning { border-color: rgba(245, 158, 11, 0.3); }
.toast.warning::before { background: var(--warning); }

/* === BACK TO TOP === */
/* Floating circular button in the bottom-right corner. Hidden until the
   user has scrolled more than 600px. Animated fade + slide-in via the
   .visible class. Sits above the toast container so it never overlaps
   with notifications. */
.back-to-top {
  position: fixed;
  bottom: 24px;
  right: 24px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--bg-3);
  color: var(--text-primary);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-md);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 2900;
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity 0.25s ease, transform 0.25s ease, visibility 0s linear 0.25s, background 0.2s ease, border-color 0.2s ease;
  padding: 0;
}
.back-to-top.visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity 0.25s ease, transform 0.25s ease, visibility 0s, background 0.2s ease, border-color 0.2s ease;
}
.back-to-top:hover {
  background: var(--bg-4);
  border-color: var(--border-hover);
}
.back-to-top:active {
  transform: translateY(0) scale(0.95);
}
@media (max-width: 768px) {
  .back-to-top {
    /* Lift above the fixed bottom-nav (approx 64px + safe-area) so tapping
       "back to top" doesn't fall behind the nav bar. */
    bottom: calc(80px + env(safe-area-inset-bottom, 0));
    right: 16px;
    width: 40px;
    height: 40px;
  }
}
@media (prefers-reduced-motion: reduce) {
  .back-to-top,
  .back-to-top.visible {
    transition: opacity 0.1s linear, visibility 0s;
    transform: none;
  }
}

/* Hide both floating UI overlays while the fullscreen media modal is
   open - they would otherwise sit on top of the modal and block the
   image. The .modal-open class is toggled by player.js in openModal/
   closeModal. */
body.modal-open .back-to-top,
body.modal-open .pull-to-refresh {
  display: none !important;
}

.shortcut-help-modal {
  max-width: 480px;
  text-align: left;
}
.shortcut-help-title {
  font-family: var(--font-display);
  font-size: 18px;
  margin-bottom: var(--space-4);
}
.shortcut-help-list {
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: var(--space-5);
  row-gap: var(--space-2);
  margin-bottom: var(--space-5);
}
.shortcut-help-list dt {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--text-primary);
  background: var(--bg-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 2px 8px;
  min-width: 40px;
  text-align: center;
}
.shortcut-help-list dd {
  color: var(--text-secondary);
  align-self: center;
}

/* === PULL TO REFRESH === */
/* Indicator shown when the user is at the top of the page and pulls down
   past the threshold. Driven by inline transform/height via JS. The
   .refreshing class adds a spinning animation while the page reloads. */
.pull-to-refresh {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 0 20px;
  height: 0;
  overflow: hidden;
  z-index: 2500;
  background: var(--bg-2);
  color: var(--text-secondary);
  font-size: 14px;
  transition: height 0.2s ease, background 0.2s ease, color 0.2s ease;
  pointer-events: none;
}
.pull-to-refresh-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.2s ease;
}
.pull-to-refresh.refreshing {
  height: 60px;
  background: var(--bg-3);
  color: var(--text-primary);
}
.pull-to-refresh.refreshing .pull-to-refresh-icon {
  animation: spin 1s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .pull-to-refresh {
    transition: none;
  }
  .pull-to-refresh.refreshing .pull-to-refresh-icon {
    animation: none;
  }
}

/* Mobile: скрываем UI-элементы, ориентированные на десктоп.
   - pull-to-refresh: индикатор + JS-гейт по display:none в player.js
   - density-picker: на маленьких экранах CSS grid уже даёт разумную
     плотность, ручной выбор только съедает место в filter-row */
@media (max-width: 768px) {
  .pull-to-refresh,
  .density-picker {
    display: none !important;
  }

  /* === Mobile scroll perf ===
     На /collections скролл плавный, а в галерее/избранном — тормозит.
     Разница: медиа-карточки нагружают compositing тяжёлыми эффектами,
     которые GPU мобильных чипов вытягивают плохо. Убираем всё, что
     мобилке заведомо не нужно и не заметно на глаз. */

  /* backdrop-filter: blur(8px) на КАЖДОЙ карточке × 2-3 бэйджа =
     compositing-очередь при быстром скролле визуально даёт 20-30fps.
     Замещаем на непрозрачный фон — визуально почти то же самое, но
     без per-frame пересчёта backdrop'а. */
  .card-age,
  .card-favorite,
  .card-play,
  .card-video-badge {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    background: rgba(0, 0, 0, 0.55);
  }
  .card-favorite.active { background: transparent; }

  /* opacity+translateY animation на КАЖДОЙ карточке при появлении.
     На быстром скролле десятки карточек анимируются одновременно —
     GPU compositing захлёбывается. Заодно снимаем transition, чтобы
     hover-эффект (которого на touch и так нет) не создавал listener. */
  .media-card {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    /* На мобильном карточка ≈ 180×240 (не 260×340 как на десктопе),
       правильный hint для content-visibility. */
    contain-intrinsic-size: 180px 240px;
  }
  .media-card:hover {
    transform: none !important;
    box-shadow: none !important;
  }
  /* Hover-preview для видео тоже не нужна на touch — pointerenter
     срабатывает по тапу и крутит анимированный WebP; лучше пусть
     остаётся статическая миниатюра. JS уже гейт'ит по (hover: hover),
     но CSS-подстраховка на случай если кто-то мимо гейта его добавит. */
  .card-preview { display: none !important; }
}

/* === SKELETON === */
.skeleton-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 16px;
  margin-top: 16px;
}

.skeleton-card {
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  position: relative;
  transition: var(--transition);
}

.skeleton-thumb {
  width: 100%;
  aspect-ratio: 1;
  background: linear-gradient(90deg, var(--bg-3) 25%, var(--bg-4) 50%, var(--bg-3) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
}

.skeleton-controls {
  padding: 10px;
  display: flex;
  gap: 6px;
}

.skeleton-line {
  height: 28px;
  flex: 1;
  background: linear-gradient(90deg, var(--bg-3) 25%, var(--bg-4) 50%, var(--bg-3) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
  border-radius: var(--radius-sm);
}

.skeleton-line.short {
  max-width: 48px;
}

/* === CONFIRM MODAL === */
.confirm-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.7);
  backdrop-filter: blur(4px);
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  animation: fadeIn 0.2s ease;
}

.confirm-modal {
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 28px 32px;
  max-width: 400px;
  width: 90%;
  text-align: center;
  animation: fadeInUp 0.25s ease;
}

.confirm-icon {
  margin-bottom: 12px;
}

.confirm-message {
  font-size: 15px;
  color: var(--text-primary);
  line-height: 1.5;
  margin-bottom: 24px;
}

.confirm-actions,
.confirm-buttons {
  display: flex;
  gap: 10px;
  justify-content: center;
}
.confirm-buttons .btn {
  min-width: 96px;
}
.confirm-title {
  font-size: 18px;
  font-weight: 700;
  color: var(--text-primary);
  margin: 0 0 8px;
}

.confirm-actions .btn {
  min-width: 100px;
}

/* === DUPLICATES === */
.dup-group {
  margin-bottom: 20px;
  padding: 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}

.dup-group-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 12px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.dup-group-items {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

.dup-card {
  width: 140px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  transition: var(--transition);
}

.dup-card:hover {
  border-color: var(--border-hover);
}

.dup-thumb {
  width: 100%;
  aspect-ratio: 3/4;
  object-fit: cover;
  cursor: pointer;
  display: block;
}

.dup-info {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px;
}

.dup-id {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
}

.dup-type {
  font-size: 14px;
}

.dup-checkbox-label {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 6px;
  border-top: 1px solid var(--border);
  cursor: pointer;
}

.dup-checkbox-label input {
  width: 18px;
  height: 18px;
  accent-color: var(--accent);
  cursor: pointer;
}

@media (max-width: 768px) {
  .admin-table {
    font-size: 13px;
  }

  .admin-table th,
  .admin-table td {
    padding: 10px 12px;
  }

  .table-container {
    overflow-x: auto;
  }

  .admin-table {
    min-width: 600px;
  }
}

@media (max-width: 1200px) {
  .admin-media-grid,
  .skeleton-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

@media (max-width: 900px) {
  .admin-media-grid,
  .skeleton-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (max-width: 600px) {
  .admin-media-grid,
  .skeleton-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* === ICON UTILITIES === */
.icon-xs { width: 12px; height: 12px; }
.icon-sm { width: 14px; height: 14px; }
.icon-md { width: 16px; height: 16px; }
.icon-lg { width: 28px; height: 28px; }
.icon-xl { width: 32px; height: 32px; }
.icon-accent { color: var(--accent-text); }
.icon-warning { color: var(--warning); }
.icon-success { color: var(--success); }
.icon-danger { color: var(--danger); }
.icon-inline { vertical-align: middle; margin-right: 6px; }

/* === UTILITY === */
.hidden { display: none; }
.mt-1 { margin-top: 6px; }
.mt-2 { margin-top: 12px; }
.mt-3 { margin-top: 20px; }
.mb-1 { margin-bottom: 6px; }
.mb-2 { margin-bottom: 8px; }
.mb-3 { margin-bottom: 12px; }
.ml-1 { margin-left: 4px; }
.grid-full { grid-column: 1 / -1; }
.flex-between { display: flex; align-items: center; justify-content: space-between; }
.flex-gap-sm { display: flex; gap: 8px; }
.spinner-sm { width: 16px; height: 16px; border-width: 2px; }
.age-static { position: static; font-size: 11px; }
.error-page { padding-top: 120px; }

/* === DYNAMIC MODALS === */
.new-token-modal {
  background: var(--surface);
  padding: 24px;
  border-radius: 12px;
  max-width: 520px;
  width: 90%;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 1001;
}

.new-token-modal h3 {
  margin: 0 0 12px;
}

.new-token-modal p {
  color: var(--text-muted);
  margin-bottom: 16px;
}

.new-token-row {
  display: flex;
  gap: 8px;
  margin-bottom: 16px;
}

.new-token-value {
  flex: 1;
  background: var(--bg);
  padding: 10px 12px;
  border-radius: 6px;
  word-break: break-all;
}

.preview-media {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.modal-media {
  width: 100%;
  height: 100%;
  object-fit: contain;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}

/* Универсальная иконочная кнопка — используется в actions коллекций
   (список, заголовок внутри коллекции). Вынесен базовый класс, чтобы
   и .collection-card-actions .icon-btn, и .collection-heading-actions
   .icon-btn наследовали одну "рамку" и не выглядели голыми. */
.icon-btn {
  width: 32px;
  height: 32px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-2);
  color: var(--text-primary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
  transition: var(--transition);
  text-decoration: none;
}
.icon-btn:hover {
  background: var(--bg-3);
  border-color: var(--accent);
  color: var(--accent-text);
}
.icon-btn.danger:hover {
  color: var(--danger);
  border-color: var(--danger);
  background: var(--bg-3);
}
.icon-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* === COLLECTIONS ===
   Стили для страницы /collections, отдельной коллекции /collections/:id,
   popup "+ в коллекцию", prompt-диалога. */

.collections-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 8px 0 20px;
  flex-wrap: wrap;
}
.collections-header-title {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-size: 24px;
  font-weight: 600;
  letter-spacing: -0.4px;
  color: var(--text-primary);
}
/* Пока коллекций нет, JS оставляет счётчик пустым — без этого правила
   рядом с заголовком висела пустая пилюля. */
.collections-header-count:empty {
  display: none;
}
.collections-header-count {
  font-size: 14px;
  font-weight: 500;
  color: var(--text-secondary);
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 2px 10px;
}

.collections-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 16px;
}

.collection-card {
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  cursor: pointer;
  transition: var(--transition);
  display: flex;
  flex-direction: column;
  position: relative;
}
.collection-card:hover {
  border-color: var(--border-hover);
  background: var(--bg-3);
}
.collection-card-preview {
  position: relative;
  aspect-ratio: 16 / 10;
  background: var(--bg-3);
  overflow: hidden;
}
/* Три миниатюры внахлёст — визуальный намёк на "стопку" */
.collection-thumb {
  position: absolute;
  width: 70%;
  height: 78%;
  object-fit: cover;
  border-radius: 8px;
  border: 2px solid var(--bg-2);
  transition: transform 0.3s;
}
.collection-thumb-1 { top: 8%;  left: 15%; z-index: 3; }
.collection-thumb-2 { top: 12%; left: 8%;  z-index: 2; transform: rotate(-4deg); opacity: 0.9; }
.collection-thumb-3 { top: 12%; left: 22%; z-index: 1; transform: rotate(4deg);  opacity: 0.85; }
.collection-card:hover .collection-thumb-2 { transform: rotate(-6deg) translateX(-4px); }
.collection-card:hover .collection-thumb-3 { transform: rotate(6deg)  translateX(4px);  }
.collection-card-empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
}
.collection-card-body {
  padding: 14px 16px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 60px;
}
.collection-card-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.collection-card-meta {
  font-size: 12px;
  color: var(--text-secondary);
}
.collection-card-actions {
  position: absolute;
  top: 8px;
  right: 8px;
  display: flex;
  gap: 6px;
  opacity: 0;
  transition: opacity 0.15s;
  z-index: 4;
}
.collection-card:hover .collection-card-actions,
.collection-card:focus-within .collection-card-actions {
  opacity: 1;
}
.collection-card-actions .icon-btn {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.55);
  color: var(--text-primary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: var(--transition);
}
.collection-card-actions .icon-btn:hover { background: rgba(0, 0, 0, 0.75); border-color: var(--accent); }
.collection-card-actions .icon-btn.danger:hover { color: var(--danger); border-color: var(--danger); }

.collections-empty {
  text-align: center;
  padding: 64px 20px;
  color: var(--text-secondary);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
/* Классика: `.collections-empty { display: flex }` описано ниже
   `.hidden { display: none }` — при одинаковой специфичности выигрывает
   более позднее правило, поэтому empty state показывался даже с
   классом hidden. Явный override возвращает поведение утилиты. */
.collections-empty.hidden {
  display: none;
}
.collections-empty-icon { color: var(--accent-text); margin-bottom: 8px; }
.collections-empty-title { font-size: 18px; font-weight: 600; color: var(--text-primary); }
.collections-empty-text { font-size: 14px; max-width: 320px; }
.collections-empty .btn { margin-top: 12px; }

/* Заголовок внутри одной коллекции — понятно, что находишься не в галерее */
.collection-heading {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  margin: 4px 0 16px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  flex-wrap: wrap;
}
.collection-heading-back {
  color: var(--text-secondary);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 8px;
  border-radius: 6px;
  transition: var(--transition);
}
.collection-heading-back:hover { color: var(--text-primary); background: var(--bg-3); }
.collection-heading-icon {
  color: var(--accent-text);
  display: inline-flex;
  align-items: center;
}
.collection-heading-name {
  font-size: 18px;
  font-weight: 700;
  color: var(--text-primary);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.collection-heading-count {
  font-size: 13px;
  color: var(--text-secondary);
  background: var(--bg-3);
  border-radius: 20px;
  padding: 2px 10px;
}
.collection-heading-actions {
  display: flex;
  gap: 6px;
}
/* Специальный стиль для заголовка при 404 — коллекция не найдена.
   Убираем accent-полосу и лишние отступы, оставляем только
   breadcrumb "← К коллекциям", чтобы пользователь мог вернуться. */
.collection-heading-empty {
  border-left: 1px solid var(--border);
  padding: 8px 12px;
}
.collection-heading-empty .collection-heading-back {
  gap: 6px;
}
.collection-heading-empty .collection-heading-back span {
  font-size: 14px;
}

/* Popup "+" рядом с ❤️ в модалке медиа */
.collections-popup {
  position: fixed;
  z-index: 10000;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  max-width: 320px;
  max-height: 400px;
}
.collections-popup-header {
  padding: 10px 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-bottom: 1px solid var(--border);
}
.collections-popup-scroll {
  overflow-y: auto;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  scrollbar-width: thin;
  scrollbar-color: var(--border-hover) transparent;
}
.collections-popup-scroll::-webkit-scrollbar { width: 8px; }
.collections-popup-scroll::-webkit-scrollbar-thumb {
  background: var(--border-hover);
  border-radius: 4px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
.collections-popup-option {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--text-primary);
  font-size: 14px;
  user-select: none;
  transition: background 0.12s;
}
.collections-popup-option:hover { background: var(--bg-3); }
.collections-popup-option input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
  cursor: pointer;
  flex-shrink: 0;
}
.collections-popup-option > span:nth-of-type(1) { flex: 1; }
.collections-popup-count {
  font-size: 12px;
  color: var(--text-secondary);
  background: var(--bg-3);
  border-radius: 10px;
  padding: 1px 8px;
}
.collections-popup-newbtn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  justify-content: center;
  padding: 10px 12px;
  background: transparent;
  color: var(--accent-text);
  border: none;
  border-top: 1px solid var(--border);
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  transition: background 0.12s;
}
.collections-popup-newbtn:hover { background: var(--bg-3); }

/* Prompt-диалог (создать/переименовать коллекцию) */
.prompt-input {
  width: 100%;
  padding: 10px 12px;
  font-size: 15px;
  font-family: inherit;
  color: var(--text-primary);
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  outline: none;
  transition: var(--transition);
  margin: 8px 0 12px;
}
.prompt-input:focus {
  border-color: var(--accent);
  box-shadow: var(--focus-ring);
}
.prompt-input-error {
  border-color: var(--danger);
  animation: prompt-shake 0.3s;
}
@keyframes prompt-shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-4px); }
  75% { transform: translateX(4px); }
}

/* Кнопка "+" рядом с ❤️ в модалке медиа. Совпадает по цветам, обводке
   и «морозной» подложке с .modal-close / .modal-edit / .modal-favorite,
   чтобы вся плавающая обвязка модалки выглядела единым сетом кнопок. */
.modal-add-collection {
  position: absolute;
  bottom: 20px;
  right: 76px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--overlay-scrim);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid var(--overlay-hairline);
  color: white;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
  transition: var(--transition);
  z-index: 5;
}
.modal-add-collection:hover {
  background: var(--overlay-scrim-strong);
  transform: scale(1.08);
}
.modal-add-collection.active {
  background: var(--overlay-scrim-strong);
  border-color: rgba(255, 255, 255, 0.35);
}

@media (max-width: 768px) {
  .collections-grid { grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px; }
  .collection-card-actions { opacity: 1; }
  .collection-heading { padding: 10px 12px; }
  .collection-heading-name { font-size: 16px; }
  .modal-add-collection { bottom: 88px; right: 16px; }
}

/* === CHOICE DIALOG (showChoice) ===
   Радио-стиль список: кликом сразу выбираем. Разметка совпадает с
   confirm-overlay/confirm-modal, чтобы шапка и OK/Отмена выглядели
   одинаково по всему приложению. */
.choice-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 12px 0 4px;
}
.choice-item {
  appearance: none;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-primary);
  padding: 12px 14px;
  border-radius: var(--radius-md);
  font-size: 14px;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  transition: var(--transition);
  font-family: inherit;
}
.choice-item:hover {
  background: var(--surface-hover);
  border-color: var(--border-hover);
}
.choice-item.selected {
  background: var(--accent-soft);
  color: var(--accent-text);
  border-color: var(--accent-line);
}

/* === SLIDESHOW BAR (внутри модалки) ===
   Полоса прогресса + Play/Pause + Exit. При активном слайдшоу модалка
   получает класс .slideshow-active, что не даёт бару исчезнуть по idle
   (см. resetIdleTimer). */
.slideshow-bar {
  position: absolute;
  left: 50%;
  bottom: 76px;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
  background: var(--overlay-scrim);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid var(--overlay-hairline);
  border-radius: 999px;
  color: white;
  z-index: 6;
  min-width: 220px;
  max-width: min(420px, calc(100vw - 32px));
}
.slideshow-progress {
  flex: 1 1 auto;
  height: 4px;
  background: rgba(255, 255, 255, 0.18);
  border-radius: 2px;
  overflow: hidden;
}
.slideshow-progress-fill {
  height: 100%;
  width: 0%;
  background: var(--accent);
  border-radius: 2px;
  transition: width 90ms linear;
}
.slideshow-controls {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}
.slideshow-btn {
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.18);
  color: white;
  cursor: pointer;
  padding: 0;
  transition: var(--transition);
}
.slideshow-btn:hover {
  background: rgba(255, 255, 255, 0.2);
  transform: scale(1.08);
}
.slideshow-interval {
  font-size: 12px;
  font-weight: 600;
  opacity: 0.85;
  min-width: 26px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* CRITICAL: hidden-атрибут даёт `display: none`, но у нас в правиле
   выше `.slideshow-bar { display: inline-flex; }` — CSS-specificity
   перебивает атрибут, и bar остаётся видимым даже с hidden=true.
   Явное правило со specificity класса чинит. */
.slideshow-bar[hidden] { display: none !important; }

/* idle-режим прячет .modal-* контролы через opacity: у нас .slideshow-bar
   должна оставаться, потому что во время слайдшоу модалка вообще НЕ
   переходит в idle (см. resetIdleTimer). Но всё равно перестраховываемся:
   пока slideshow-active — бар всегда виден. */
.modal.slideshow-active .slideshow-bar { opacity: 1; pointer-events: auto; }

/* Презентационный режим: на время слайдшоу оставляем ТОЛЬКО медиа и
   .slideshow-bar. Всё остальное (возраст, ❤, +, ×, редактирование,
   prev/next) прячем — иначе на десктопе панель слайдшоу наезжает на
   плавающие кнопки вокруг модалки. Клавиатура при этом работает как
   обычно: ←/→ ручная навигация, Esc — выход из слайдшоу. */
.modal.slideshow-active .modal-bottom-bar,
.modal.slideshow-active .modal-close,
.modal.slideshow-active .modal-edit,
.modal.slideshow-active .modal-add-collection,
.modal.slideshow-active .modal-nav {
  display: none !important;
}

@media (max-width: 768px) {
  .slideshow-bar {
    bottom: 96px;
    min-width: 200px;
    padding: 6px 10px;
    gap: 10px;
  }
  .slideshow-btn { width: 30px; height: 30px; }
}

/* Кнопка "Слайдшоу" в фильтрах — используем .btn-secondary "как есть",
   тут только компактность на узких экранах — иначе панель фильтров
   разрастается на две строки. */
@media (max-width: 640px) {
  #slideshowBtn { padding: 0 12px; }
  #slideshowBtn i { margin: 0; }
}

