/* =========================================
   Game Detail Page
   Used on: game-happy-abcs.html (and future game pages)
   Follow BEM naming: .block__element--modifier
   ========================================= */

/* =========================================
   Game Hero
   ========================================= */
.game-hero {
  padding: 48px 0 80px;
  background-color: var(--color-white);
}

.game-hero__inner {
  max-width: 1150px;
  margin: 0 auto;
  padding: 0 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 26px;
}

/* Title */
.game-hero__title {
  font-size: 64px;
  font-weight: 900;
  line-height: 1.1;
  letter-spacing: -0.5px;
  color: var(--color-brand-primary);
  text-align: center;
  margin: 0;
}

/* Description */
.game-hero__desc {
  font-size: 28px;
  font-weight: 400;
  line-height: 1.35;
  color: var(--color-text-secondary);
  text-align: center;
  /* max-width: 660px; */
  margin: 0;
}

/* Video wrapper */
.game-hero__video-wrap {
  width: 100%;
  margin-top: 16px;
  aspect-ratio: 16 / 9;
  border-radius: 25px;
  overflow: hidden;
  background-color: #000;
  box-shadow: 0 4px 32px rgba(0, 0, 0, 0.14);
  /* Deliberately borderless — the 2px frame is drawn by ::after below. A real border
     would come out of the content box (box-sizing:border-box), leaving the inside
     1098x616 = 1.7825 instead of 16:9, and the player has to be exactly 16:9 or
     YouTube letterboxes the video inside it. Outer size is unchanged either way,
     since aspect-ratio applies to the border box. */
  border: 0;
  position: relative;
}

/* The lavender frame, as an overlay rather than a border, so it costs the content box
   nothing. pointer-events:none keeps the whole-video click-through working. */
.game-hero__video-wrap::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 2px solid var(--color-lavender-blue);
  border-radius: inherit;
  pointer-events: none;
  z-index: 2;
}

/* The line across the middle of the hero video (COR-2025) is a compositing seam, and
   the trigger is having ANY transform on the iframe — not the scale factor. Measured on
   a frozen frame: translate(-50%,-50%) with scale 1.04, 1.02 and even 1.0 all produce an
   identical ~14-luminance dark row at exactly y=310 on a 620px box (dead centre), and
   transform:none produces none. A scaled/translated out-of-process iframe gets composited
   as its own resampled layer, and with a fractional height (1098/1.7778 = 617.6) the
   half-pixel split lands mid-frame and shows as a hairline.
   So: no transform at all. That is only possible because the wrap is now genuinely 16:9
   on the inside (see the border note above), which means inset:0 already gives an exactly
   16:9 player — no letterbox to hide, so nothing to bleed over with a scale.
   transform:none must be explicit: this iframe also carries .bg-video, whose scale(1.25)
   is meant for the decorative background loops. (0,1,1) beats .bg-video's (0,1,0). */
.game-hero__video-wrap iframe {
  display: block;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  transform: none;
}

/* Mute / unmute toggle for the autoplaying hero video (starts muted, browsers
   require that for autoplay). Icon is a speaker with an X (muted, default) or
   sound-wave lines (unmuted) — swapped via the --unmuted modifier in JS. */
.game-hero__mute-btn {
  /* Temporarily hidden per COR-2031 — remove this line to bring it back. */
  display: none;
  position: absolute;
  right: 16px;
  bottom: 16px;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background-color: rgba(0, 0, 0, 0.45);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 55%;
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpolygon%20points='3,9%208,9%2013,4%2013,20%208,15%203,15'%20fill='white'/%3E%3Cline%20x1='16'%20y1='9'%20x2='21'%20y2='15'%20stroke='white'%20stroke-width='2'%20stroke-linecap='round'/%3E%3Cline%20x1='21'%20y1='9'%20x2='16'%20y2='15'%20stroke='white'%20stroke-width='2'%20stroke-linecap='round'/%3E%3C/svg%3E");
  cursor: pointer;
  transition: background-color 0.15s ease, transform 0.15s ease;
  z-index: 2;
}

.game-hero__mute-btn:hover {
  background-color: rgba(0, 0, 0, 0.65);
  transform: scale(1.06);
}

.game-hero__mute-btn--unmuted {
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpolygon%20points='3,9%208,9%2013,4%2013,20%208,15%203,15'%20fill='white'/%3E%3Cpath%20d='M16%208c1.5%201.2%201.5%206.8%200%208'%20fill='none'%20stroke='white'%20stroke-width='2'%20stroke-linecap='round'/%3E%3Cpath%20d='M18.5%205c3%203%203%2011%200%2014'%20fill='none'%20stroke='white'%20stroke-width='2'%20stroke-linecap='round'/%3E%3C/svg%3E");
}

@media (max-width: 990px) {
  .game-hero__mute-btn {
    width: 32px;
    height: 32px;
    right: 10px;
    bottom: 10px;
  }
}

/* Whole-video click-through to its real page (YouTube watch page, or the raw
   file URL for a self-hosted fallback) — opens in a new tab. The iframe/video
   itself is given pointer-events:none so the click always lands on the wrap;
   the mute button sits on top with its own (default) pointer-events so it
   still intercepts its own clicks before they'd reach the wrap. */
.game-hero__video-wrap[data-video-link]:not([data-video-link=""]) {
  cursor: pointer;
}

.game-hero__video-wrap iframe,
.game-hero__video-wrap video {
  pointer-events: none;
}

/* Covers the YouTube branding/controls flash on load — see the markup comment
   in Details.cshtml. hero-video-mute.js hides this as soon as it confirms
   real playback via the player's postMessage state (adds --playing below).
   This animation-delay is only the fallback for if that handshake never
   arrives, so the cover can never get permanently stuck — kept long since
   it's now a safety net, not the primary trigger (COR-2025). */
.game-hero__video-cover {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  z-index: 1;
  /* Fallback only, for a handshake that never arrives. Must not undercut
     REVEAL_AFTER in hero-video-mute.js or it uncovers while YouTube's chrome is
     still on screen — that is the bug it is meant to be protecting. Note it is
     timed from page load while REVEAL_AFTER is timed from playback start, and
     playback begins a second or two after load, so this needs real headroom
     over it rather than a matching number. */
  animation: game-hero-video-cover-out 0.5s ease forwards;
  animation-delay: 4.5s;
}

/* Both states win over the animation above (author !important beats CSS
   Animations in the cascade) so playback confirmation can hide the cover
   immediately even mid-delay, without fighting or restarting the fallback
   animation — and so --covering can bring it back afterwards, which the
   animation's `forwards` fill would otherwise make impossible.
   The delayed `visibility` step is what makes the fade actually visible:
   visibility is not interpolated, so switching it at 0s cut the element out
   instantly and the opacity transition never showed. */
.game-hero__video-cover--playing {
  opacity: 0 !important;
  visibility: hidden !important;
  transition: opacity 0.4s ease, visibility 0s linear 0.4s;
}

/* Re-armed between videos — see the loop note in hero-video-mute.js. Comes back
   faster than it leaves so it is always in place before YouTube repaints. */
.game-hero__video-cover--covering {
  opacity: 1 !important;
  visibility: visible !important;
  transition: opacity 0.12s ease, visibility 0s;
}

@keyframes game-hero-video-cover-out {
  to {
    opacity: 0;
    visibility: hidden;
  }
}

.game-hero__video-hint {
  position: absolute;
  top: 16px;
  left: 16px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  border-radius: 999px;
  background-color: rgba(0, 0, 0, 0.55);
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity 0.15s ease, transform 0.15s ease;
  pointer-events: none;
  z-index: 2;
}

.game-hero__video-wrap[data-video-link]:not([data-video-link=""]):hover .game-hero__video-hint {
  opacity: 1;
  transform: translateY(0);
}

@media (max-width: 990px) {
  .game-hero__video-hint {
    top: 10px;
    left: 10px;
    font-size: 11px;
    padding: 6px 10px;
  }
}

/* =========================================
                               Skills They Build
                               ========================================= */
.game-skills {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  margin-top: 119px;
}

@media (max-width: 990px) {
  .game-skills {
    margin-top: 39px;
    gap: 20px;
  }
}

.game-skills__title {
  font-size: 42px;
  font-weight: 800;
  color: var(--color-text-primary);
  text-align: center;
  margin: 0;
}

@media (max-width: 990px) {
  .game-skills__title {
    font-size: 20px;
    font-weight: 700;
  }
}

.game-skills__tags {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 34px 26px;
}

@media (max-width: 990px) {
  .game-skills__tags {
    gap: 12px 12px;
  }
}

.game-skills__tag {
  display: inline-block;
  padding: 14px 10px;
  border-radius: var(--radius-full);
  font-size: 23px;
  font-weight: 500;
  line-height: 1;
}

@media (max-width: 990px) {
  .game-skills__tag {
    font-size: 12px;
    font-weight: 500;
    padding: 6px 10px;
  }
}

.game-skills__tag--lavender {
  color: var(--color-lime-lavender);
  background-color: var(--color-lime-lavender-subtle);
}

.game-skills__tag--green {
  color: var(--color-lime-green);
  background-color: var(--color-lime-green-subtle);
}

.game-skills__tag--pink {
  color: var(--color-lime-pink);
  background-color: var(--color-lime-pink-subtle);
}

.game-skills__tag--blue {
  color: var(--color-pretty-blue);
  background-color: var(--color-pretty-blue-subtle);
}

.game-skills__tag--orange {
  color: var(--color-guide-orange);
  background-color: var(--color-guide-orange-subtle);
}

/* =========================================
                               Explore More Slider
                               ========================================= */
.explore-more {
  padding: 64px 0 80px;
  overflow: hidden;
}

.explore-more__title {
  font-size: 44px;
  font-weight: 800;
  color: var(--color-brand-primary);
  text-align: center;
  margin: 0px 0 31px;
}

/* The scrollbar inset is driven through Swiper's own custom property rather than
   by overriding left/width (COR-2036). Swiper's base rule for the track is
   `.swiper-horizontal > .swiper-scrollbar` — specificity (0,2,0), the same as any
   `.swiper-scrollbar.explore-more__scrollbar` override we can write — and the
   portal lazy-loads swiper-bundle.min.css into <head> AFTER game-detail.css, so
   on a specificity tie Swiper wins on order: our width/left were silently dropped
   and the track rendered at Swiper's default `left:1%; width:calc(100% - 2%)`,
   then got shifted further right by our own margin. That is the line that started
   past the first card and ran off the right edge of the page.
   Setting --swiper-scrollbar-sides-offset instead makes Swiper's own rule compute
   the inset we want, so there is nothing to out-specify — and because Swiper sizes
   the drag thumb off this element's clientWidth, its travel range matches the
   visible track by construction. The offset equals the swiper's horizontal padding
   so the track starts and ends exactly on the card edges. */
.explore-more__swiper {
  padding: 8px 41px 16px !important;
  --swiper-scrollbar-sides-offset: 41px;
}

@media (max-width: 990px) {
  .explore-more__swiper {
    padding: 8px 16px 14px !important;
    --swiper-scrollbar-sides-offset: 16px;
  }
}

/* .swiper-scrollbar.explore-more__scrollbar (0,2,0) beats Swiper's base
   .swiper-scrollbar{background:#0000001a} regardless of load order (it is (0,1,0))
   — otherwise the faint gray track ("long line") shows behind the thumb. */
.swiper-scrollbar.explore-more__scrollbar {
  bottom: 0 !important;
  height: 4px;
  background: transparent;
  border-radius: 2px;
}

.explore-more__scrollbar .swiper-scrollbar-drag {
  background: var(--color-brand-primary);
  border-radius: 2px;
  opacity: 0.2;
}

.explore-more__scrollbar .swiper-scrollbar-drag:active {
  cursor: grabbing;
}

/* Force all slides to stretch to the tallest card's height */
.explore-more__swiper .swiper-wrapper {
  align-items: stretch;
}

/* .swiper-slide.explore-more__slide (0,2,0) beats Swiper's base .swiper-slide{height:100%}
   regardless of load order (portal lazy-loads swiper CSS AFTER game-detail.css). height:auto
   + the wrapper's align-items:stretch is what makes every explore card the same height. */
.swiper-slide.explore-more__slide {
  width: 280px;
  height: auto;
  display: flex;
}

.explore-more__slide .game-card {
  width: 100%;
  height: 100%;
}
@media (max-width: 990px) {
  .explore-more__card {
    border-radius: 12px;
  }
  .explore-more__card-title {
    font-size: 12px;
  }
  .explore-more__card-desc {
    font-size: 10px;
  }
}
/* =========================================
                               Responsive
                               ========================================= */
@media (max-width: 990px) {
  .game-hero {
    padding: 32px 0 56px;
  }

  .game-hero__inner {
    padding: 0 20px;
    gap: 17px;
  }

  .game-hero__title {
    font-size: 28px;
  }

  .game-hero__desc {
    font-size: 16px;
    font-weight: 500;
  }

  .game-hero__video-wrap {
    border-radius: 20px;
    margin-top: -2px;
  }

  .explore-more {
    padding: 0px 0 36px;
  }

  .explore-more__title {
    font-size: 20px;
    margin-bottom: 14px;
  }

  .swiper-slide.explore-more__slide {
    width: 220px;
  }
}
