/* Liquid Glass design system for Adrian's birthday site.
   Pastel gradient backdrop + genuine Apple-style Liquid Glass surfaces
   (WWDC 2025 / iOS 26 material): highly transparent, refractive/lensing,
   with a bright specular highlight along the top edge — not flat frosted
   glassmorphism. See .glass-panel / .glass-panel-soft / .glass-pill below;
   each uses a `::before` layer for the blur+distortion+highlight so the
   real content on top always stays crisp. */

:root {
  --ink: #1a1226;
  --ink-soft: #3a2a45;
  --ink-muted: #5c4c66;
  --ink-faint: #8a7891;
  --ink-faintest: #a598ab;
  --pink: #ff6fb0;
  --orange: #ff9a56;
  --purple: #7c3aed;
  --teal: #5ad6cd;
  --bg-base: #fdfaf6;
  /* Genuine Liquid Glass is much clearer than frosted glassmorphism: low
     background opacity so the pastel gradient reads vividly through it. */
  --glass-bg: rgba(255, 255, 255, 0.16);
  --glass-bg-strong: rgba(255, 255, 255, 0.20);
  --glass-border: rgba(255, 255, 255, 0.35);
  --glass-shadow: 0 20px 60px rgba(31, 38, 135, 0.22);
  --glass-shadow-soft: 0 8px 32px rgba(31, 38, 135, 0.14);
  --glass-inset: inset 0 1px 1px rgba(255, 255, 255, 0.6);
  /* Specular highlight stack: bright crisp glint on the top edge (light
     catching a curved edge), a faint bounce-light line on the bottom edge,
     plus a soft outer lift shadow. */
  --glass-specular:
    inset 0 1.5px 0 rgba(255, 255, 255, 0.85),
    inset 0 -1px 0 rgba(255, 255, 255, 0.12),
    0 20px 60px rgba(31, 38, 135, 0.22);
  --glass-specular-soft:
    inset 0 1.5px 0 rgba(255, 255, 255, 0.75),
    inset 0 -1px 0 rgba(255, 255, 255, 0.1),
    0 8px 32px rgba(31, 38, 135, 0.14);
  --radius-lg: 32px;
  --radius-md: 20px;
  --radius-sm: 14px;
  --gradient-primary: linear-gradient(135deg, var(--pink), var(--orange));
  --gradient-heading: linear-gradient(135deg, var(--purple), var(--pink) 55%, var(--orange));
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  min-height: 100%;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Rounded', system-ui, 'Segoe UI', sans-serif;
  color: var(--ink);
  background:
    radial-gradient(circle at 15% 20%, rgba(255, 111, 176, 0.5), transparent 40%),
    radial-gradient(circle at 85% 15%, rgba(255, 196, 102, 0.45), transparent 40%),
    radial-gradient(circle at 75% 85%, rgba(124, 109, 255, 0.4), transparent 45%),
    radial-gradient(circle at 20% 85%, rgba(90, 214, 205, 0.35), transparent 45%),
    var(--bg-base);
  background-attachment: fixed;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--purple); }
a:hover { color: var(--pink); }
::selection { background: rgba(255, 111, 176, 0.35); }

img { max-width: 100%; display: block; }

button {
  font-family: inherit;
  cursor: pointer;
}

button:disabled {
  cursor: not-allowed;
  opacity: 0.6;
}

/* ---------- Glass primitives ----------
   Real Liquid Glass architecture: the element itself stays fully
   transparent and only establishes a self-contained stacking context
   (isolation: isolate). A `::before` sitting behind the content (z-index:
   -1, inset: 0) carries the translucent tint, backdrop blur/saturation,
   and the SVG refraction filter. Because it's a separate layer, the
   distortion filter never touches the text/icons rendered as normal
   in-flow content on top of it — those simply paint above a negative
   z-index child within the isolated stacking context, no extra z-index
   needed on ordinary children. */

.glass-panel,
.glass-panel-soft,
.glass-pill {
  position: relative;
  isolation: isolate;
  background: transparent;
  border: 1px solid var(--glass-border);
}

.glass-panel::before,
.glass-panel-soft::before,
.glass-pill::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  pointer-events: none;
  filter: url(#liquid-glass-distortion);
}

.glass-panel {
  box-shadow: var(--glass-specular);
  border-radius: var(--radius-lg);
}

.glass-panel::before {
  background: var(--glass-bg);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
}

.glass-panel-soft {
  box-shadow: var(--glass-specular-soft);
  border-radius: var(--radius-md);
}

.glass-panel-soft::before {
  background: var(--glass-bg);
  backdrop-filter: blur(18px) saturate(180%);
  -webkit-backdrop-filter: blur(18px) saturate(180%);
}

.glass-pill {
  box-shadow: var(--glass-specular-soft);
  border-radius: 999px;
}

.glass-pill::before {
  background: var(--glass-bg-strong);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
}

.btn {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border: none;
  border-radius: 999px;
  font-weight: 800;
  font-size: 14px;
  padding: 14px 28px;
  color: #fff;
  background: var(--gradient-primary);
  box-shadow: 0 10px 30px rgba(255, 111, 176, 0.4);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}

/* Sheen sweep: a soft diagonal highlight that glides across on hover,
   suggesting the light-catching behaviour of a curved glass edge. Kept to
   a CSS keyframe animation on a ::after layer (no displacement) so button
   text stays perfectly crisp. */
.btn::after,
.btn-secondary::after,
.btn-ghost::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(
    115deg,
    transparent 20%,
    rgba(255, 255, 255, 0.55) 48%,
    rgba(255, 255, 255, 0.55) 52%,
    transparent 80%
  );
  background-size: 250% 250%;
  background-position: 130% 130%;
  opacity: 0;
  transition: opacity 0.15s ease;
}

.btn:hover:not(:disabled)::after,
.btn-secondary:hover:not(:disabled)::after,
.btn-ghost:hover:not(:disabled)::after {
  opacity: 1;
  animation: sheenSweep 1.1s ease forwards;
}

@keyframes sheenSweep {
  from { background-position: 130% 130%; }
  to { background-position: -30% -30%; }
}

.btn:hover:not(:disabled) { transform: translateY(-1px); box-shadow: 0 14px 34px rgba(255, 111, 176, 0.5); }
.btn:active:not(:disabled) { transform: translateY(0); }

.btn-secondary {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: rgba(124, 58, 237, 0.12);
  color: var(--purple);
  box-shadow: none;
}

.btn-ghost {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: rgba(0, 0, 0, 0.06);
  color: var(--ink-muted);
  box-shadow: none;
}

.btn-small {
  padding: 10px 18px;
  font-size: 13px;
}

/* Icon+label buttons for the app-bar's page actions (Select, Download
   All, Help) — plain text pills in a row of similar-looking pills were
   getting missed entirely; an icon gives each one a shape to recognize
   at a glance before even reading the word. */
.btn-icon-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.btn-icon-label svg {
  width: 16px;
  height: 16px;
  flex: none;
  stroke: currentColor;
}
.btn-icon-label.btn-icon-only {
  padding-left: 12px;
  padding-right: 12px;
}

.input {
  width: 100%;
  box-sizing: border-box;
  padding: 14px 16px;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(0, 0, 0, 0.1);
  background: rgba(255, 255, 255, 0.7);
  font-size: 14px;
  font-family: inherit;
  outline: none;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.input:focus {
  border-color: var(--pink);
  background: rgba(255, 255, 255, 0.9);
}

.gradient-heading {
  background: var(--gradient-heading);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.eyebrow-pill {
  display: inline-block;
  padding: 7px 16px;
  border-radius: 999px;
  background: var(--gradient-primary);
  color: #fff;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 1.5px;
  text-transform: uppercase;
}

/* ---------- Floating blobs (ambient background motion) ---------- */

.blob-field {
  position: fixed;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}

.blob {
  position: absolute;
  border-radius: 50%;
  opacity: 0.5;
  filter: blur(2px);
  animation: blobFloat ease-in-out infinite;
}

/* Content pages (Gallery/Videos/Upload) are for looking at photos and
   filling in a form, not admiring the backdrop — competitors like Google
   Photos and Apple Shared Albums keep browsing views close to neutral so
   the actual content has the contrast to stand out. The playful vivid
   blobs stay reserved for arrival moments (Home, Song). */
.content-page .blob {
  opacity: 0.22;
  filter: blur(10px);
}

@keyframes blobFloat {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50% { transform: translate(-2%, 3%) scale(1.06); }
}

@keyframes fadeUp {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: translateY(0); }
}

.fade-up { animation: fadeUp 0.5s ease; }

/* ---------- Top nav ---------- */

.top-nav {
  position: sticky;
  top: 16px;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 24px;
  margin: 16px;
  flex-wrap: wrap;
}

.top-nav .brand {
  font-weight: 800;
  font-size: 15px;
  color: var(--ink-soft);
  white-space: nowrap;
}

.top-nav .links {
  display: flex;
  gap: 8px;
}

.nav-link {
  border: none;
  text-decoration: none;
  display: inline-block;
  font-size: 13px;
  font-weight: 700;
  padding: 10px 18px;
  border-radius: 999px;
  background: rgba(124, 58, 237, 0.12);
  color: var(--purple);
}

/* ---------- App bar (consolidated nav + page actions in one bar) ----------
   On wide screens the nav links render directly in this bar alongside the
   page's own actions (Select, Download, Help, etc). On phone widths, the
   nav moves to a fixed bottom tab bar instead (see below) — research on
   mobile nav patterns (Nielsen Norman Group et al.) consistently finds a
   hamburger-hidden nav measurably hurts task completion and discoverability
   versus an always-visible bottom tab bar for 3–5 primary destinations,
   which is exactly this site's shape (Home/Gallery/Videos/Upload/Song).
   The top bar on mobile is then just the current page's title + actions. */

.app-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.nav-menu-btn {
  display: none;
}

.app-bar-titles {
  flex: 1;
  min-width: 0;
}

.app-bar-titles .brand {
  font-weight: 800;
  font-size: 15px;
  color: var(--ink-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.app-bar-subtitle {
  display: block;
  font-size: 11px;
  color: var(--ink-faint);
  font-weight: 600;
  margin-top: 1px;
}

/* On mobile the bottom tab bar already names the current page, so
   repeating it in the top bar too just eats space the action buttons
   need to stay legible — a page with a subtitle (a live count) shows
   that alone; a page without one keeps its title since there's nothing
   else to show. */
@media (max-width: 859px) {
  .app-bar-titles:has(.app-bar-subtitle:not(:empty)) .brand {
    display: none;
  }
  .app-bar-subtitle {
    font-size: 13px;
    font-weight: 800;
    color: var(--ink-soft);
  }
}

.app-bar-actions {
  flex: none;
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: nowrap;
  padding: 5px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.4);
  border: 1px solid rgba(255, 255, 255, 0.55);
  box-shadow: inset 0 1px 2px rgba(31, 38, 135, 0.06);
}

/* A plain gap wasn't enough to read as "these buttons are a different
   thing from the nav links" once both are rows of similar pills — the
   grouped pill above helps, but on wide screens where the nav sheet sits
   inline right before it, add a visible divider too so the eye has a
   clear "navigation ends here, page controls start here" boundary. */
@media (min-width: 860px) {
  .app-bar-actions::before {
    content: '';
    width: 1px;
    align-self: stretch;
    margin: 4px 4px 4px 0;
    background: rgba(124, 58, 237, 0.18);
  }
}

.app-bar-wrap {
  position: sticky;
  top: 16px;
  z-index: 60;
  margin: 16px;
}

/* On mobile the nav lives in the bottom tab bar instead (see below), so
   the sheet is simply hidden — no dropdown, nothing to toggle. */
.nav-menu-sheet {
  display: none;
}

@media (max-width: 560px) {
  .app-bar-titles .brand { font-size: 13px; }
  .app-bar-actions { gap: 6px; }
}

/* On wider screens there's room to just show the nav links directly in
   the bar, alongside the page's own actions. */
@media (min-width: 860px) {
  .nav-menu-sheet {
    display: flex;
    position: static;
    flex-direction: row;
    min-width: 0;
    padding: 0;
    gap: 8px;
    background: none;
    box-shadow: none;
    border: none;
    transform: none;
    opacity: 1;
    pointer-events: auto;
    order: 2;
  }
  .nav-menu-sheet::before { display: none; }
  .nav-menu-sheet .nav-link {
    text-align: center;
    animation: none !important;
  }
  .app-bar-actions { order: 3; }
}

.nav-link.primary {
  background: var(--gradient-primary);
  color: #fff;
  box-shadow: 0 4px 14px rgba(255, 111, 176, 0.4);
}

/* ---------- Bottom tab bar (mobile primary nav) ----------
   Always-visible, thumb-reachable navigation for phones, replacing the
   hamburger dropdown. Research on mobile nav (Nielsen Norman Group and
   others) consistently shows a hidden hamburger nav measurably hurts
   discoverability and task completion versus a persistent tab bar for
   3–5 destinations — this site's exact shape (5 pages). Hidden by
   default; shown only below the desktop breakpoint (see media query),
   where the nav also disappears from the top app-bar so it isn't shown
   twice. */
.bottom-tab-bar {
  display: none;
}

@media (max-width: 859px) {
  body { padding-bottom: 88px; }

  .bottom-tab-bar {
    display: flex;
    position: fixed;
    left: 10px;
    right: 10px;
    bottom: 10px;
    z-index: 500;
    justify-content: space-around;
    align-items: stretch;
    padding: 6px 2px calc(6px + env(safe-area-inset-bottom));
    border-radius: 22px;
  }

  .tab-item {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    padding: 6px 2px;
    border-radius: 16px;
    text-decoration: none;
    color: var(--ink-faint);
    font-size: 10px;
    font-weight: 700;
    transition: color 0.15s ease, background 0.15s ease, transform 0.15s ease;
  }

  .tab-item svg {
    width: 22px;
    height: 22px;
    stroke: currentColor;
  }

  .tab-item:active { transform: scale(0.94); }

  .tab-item.active {
    color: var(--purple);
    background: rgba(124, 58, 237, 0.12);
  }

  /* Floating elements that otherwise sit at the very bottom of the
     screen (the select-mode action bar, the lightbox's download button)
     need to clear the tab bar instead of hiding behind it. Scoped with
     `body` for extra specificity so it reliably wins over those
     elements' own base rule regardless of which is defined later in
     this file. */
  body .selection-bar,
  body .lightbox-download {
    bottom: calc(88px + env(safe-area-inset-bottom));
  }
}

/* ---------- Layout helpers ---------- */

.page-shell {
  position: relative;
  z-index: 1;
  min-height: 100vh;
}

.center-stage {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 100px 24px 60px;
}

.container-narrow {
  max-width: 560px;
  width: 100%;
}

.container-form {
  max-width: 400px;
  width: 100%;
}

.text-muted { color: var(--ink-muted); }
.text-faint { color: var(--ink-faint); }
.text-center { text-align: center; }

/* ---------- Modal / popup ---------- */

.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(20, 10, 25, 0.35);
  backdrop-filter: blur(4px);
  padding: 24px;
}

.modal-card {
  max-width: 420px;
  width: 100%;
  padding: 32px;
}

/* Modals sit on top of the busiest part of the background and hold the most
   text guests need to actually read, so they trade the site's usual
   transparency for a near-solid card — legibility over glass-effect here.
   The distortion filter (fine for a page panel's ambient background) is
   dropped entirely since any softening works against readability. */
.modal-card::before {
  background: rgba(255, 252, 250, 0.94);
  backdrop-filter: blur(20px) saturate(140%);
  -webkit-backdrop-filter: blur(20px) saturate(140%);
  filter: none;
}

.modal-card .text-faint,
.modal-card .text-muted {
  color: var(--ink-muted);
}

/* ---------- Toast ---------- */

.toast {
  position: fixed;
  bottom: 28px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1500;
  padding: 14px 22px;
  border-radius: 999px;
  background: rgba(30, 20, 40, 0.85);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.3);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(-4px);
}

/* ---------- Upload attribution tag (photo/video tiles) ---------- */

.upload-tag {
  display: inline-block;
  max-width: 100%;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(20, 10, 25, 0.55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---------- Video grid / cards (Videos + Song pages) ---------- */

.video-grid {
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 16px;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 20px;
}

.video-grid .video-card {
  flex: 1 1 360px;
  max-width: 420px;
}

.video-card {
  padding: 14px;
}

.video-embed {
  position: relative;
  width: 100%;
  padding-top: 56.25%;
  border-radius: 18px;
  overflow: hidden;
  background: rgba(0, 0, 0, 0.35);
}

.video-embed iframe {
  border: none;
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
}

.video-card-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 10px;
  min-height: 22px;
}

.video-card {
  position: relative;
  border: 2px solid transparent;
  cursor: default;
}
.video-card.selectable { cursor: pointer; }
.video-card.selected { border-color: var(--pink); }
.video-card .check-badge {
  position: absolute;
  top: 22px;
  right: 22px;
  z-index: 2;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: rgba(255,255,255,.55);
  border: 2px solid #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  color: #fff;
  font-weight: 800;
  box-shadow: 0 2px 8px rgba(0,0,0,.25);
}
.video-card.selected .check-badge { background: var(--pink); }
.video-card.selectable .video-embed { pointer-events: none; }
.download-status {
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-faint);
}

/* Floating selection action bar — shared by Gallery + Videos select mode */
.selection-bar {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 900;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 20px;
  border-radius: 999px;
  background: rgba(30,20,40,.7);
  backdrop-filter: blur(24px) saturate(180%);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  border: 1px solid rgba(255,255,255,.2);
  box-shadow: 0 16px 40px rgba(0,0,0,.3);
  color: #fff;
  flex-wrap: wrap;
  justify-content: center;
  max-width: calc(100vw - 32px);
}

/* Larger featured layout for the Song page's two videos */
.song-grid {
  max-width: 920px;
  margin: 0 auto;
  padding: 0 16px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
  gap: 24px;
}

.song-grid .video-card { padding: 18px; }

/* ---------- Dropzone / upload progress (Upload page + admin) ---------- */

.upload-progress-track {
  width: 100%;
  height: 10px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.08);
  overflow: hidden;
}

.upload-progress-fill {
  height: 100%;
  border-radius: 999px;
  background: var(--gradient-primary);
  width: 0%;
  transition: width 0.2s ease;
}

.dropzone.dragover {
  background: rgba(255, 255, 255, 0.6) !important;
  border-color: var(--pink);
}

/* App-like "don't lock your screen" banner while an upload is in flight —
   slides in above the page content rather than just adding more text, so
   it reads as an active status rather than another line of copy. */
.upload-lock-banner {
  position: sticky;
  top: 92px;
  z-index: 55;
  max-width: 640px;
  margin: 0 auto 16px;
  padding: 12px 18px;
  border-radius: 16px;
  display: flex;
  align-items: center;
  gap: 10px;
  background: rgba(124, 58, 237, 0.14);
  border: 1px solid rgba(124, 58, 237, 0.25);
  color: var(--purple);
  font-size: 13px;
  font-weight: 700;
  transform: translateY(-12px);
  opacity: 0;
  max-height: 0;
  overflow: hidden;
  transition: transform 0.25s ease, opacity 0.25s ease, max-height 0.25s ease, margin 0.25s ease, padding 0.25s ease;
  pointer-events: none;
}
.upload-lock-banner.show {
  transform: translateY(0);
  opacity: 1;
  max-height: 80px;
  pointer-events: auto;
}
.upload-lock-banner .pulse-dot {
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--pink);
  animation: pulseDot 1.2s ease-in-out infinite;
}
@keyframes pulseDot {
  0%, 100% { transform: scale(0.85); opacity: 0.6; }
  50% { transform: scale(1.15); opacity: 1; }
}

/* Uploading-state visuals for card-style upload sections: a subtle glow
   ring while active, and a short pop when a batch finishes. */
.upload-section.is-uploading {
  box-shadow: 0 0 0 2px rgba(124, 58, 237, 0.3), var(--glass-shadow-soft);
  transition: box-shadow 0.3s ease;
}
.upload-section .status-icon {
  display: inline-block;
  animation: popIn 0.35s cubic-bezier(0.2, 0.8, 0.3, 1.4);
}
@keyframes popIn {
  0% { transform: scale(0); opacity: 0; }
  100% { transform: scale(1); opacity: 1; }
}
.thumb-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}
.thumb-strip .thumb-item {
  position: relative;
  width: 56px;
  height: 56px;
  border-radius: 10px;
  overflow: hidden;
  background: rgba(0,0,0,0.06);
  animation: fadeUp 0.3s ease;
}
.thumb-strip .thumb-item img { width: 100%; height: 100%; object-fit: cover; display: block; }
.thumb-strip .thumb-item.pending::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(255,255,255,0.5);
  animation: thumbPulse 1s ease-in-out infinite;
}
@keyframes thumbPulse {
  0%, 100% { opacity: 0.3; }
  50% { opacity: 0.7; }
}
.thumb-strip .thumb-item.done::after {
  content: '✓';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(90, 214, 205, 0.55);
  color: #fff;
  font-weight: 800;
  font-size: 18px;
}
.thumb-strip .thumb-item.failed::after {
  content: '✕';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 111, 176, 0.6);
  color: #fff;
  font-weight: 800;
  font-size: 16px;
}

@media (max-width: 640px) {
  .top-nav { margin: 10px; padding: 12px 16px; }
  .center-stage { padding: 90px 16px 40px; }
  .video-grid { grid-template-columns: 1fr; }
}

/* ---------- Reduced transparency fallback (accessibility) ---------- */

@media (prefers-reduced-transparency: reduce) {
  .glass-panel::before,
  .glass-panel-soft::before,
  .glass-pill::before {
    filter: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: #fdfaf6;
  }

  .glass-panel,
  .glass-panel-soft,
  .glass-pill {
    border-color: rgba(0, 0, 0, 0.1);
  }

  .btn::after,
  .btn-secondary::after,
  .btn-ghost::after {
    display: none;
  }
}
