/* Landing page. Everything here builds on the three materials in
   components.css - this file only arranges them. */

/* ==========================================================================
   Hero
   ========================================================================== */

.hero {
  position: relative;
  padding-top: clamp(28px, 5vw, 64px);
  overflow: hidden;
  isolation: isolate;
}


/* Short laptop screens (1280x720 and friends). The rules above fit the hero
   down to about 800px of viewport height; below that the type has to come
   down another step or the store buttons fall under the fold. */


.hero__inner {
  display: grid;
  gap: clamp(24px, 5vw, 64px);
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  align-items: center;
  padding-bottom: clamp(70px, 11vw, 140px);
}

.hero__wordmark {
  width: min(420px, 78vw);
  margin-bottom: clamp(var(--s3), 2.2vh, var(--s5));
  filter: drop-shadow(0 10px 16px rgba(9, 52, 96, 0.32));
}

.hero__title {
  font-size: clamp(2rem, 5vw, 3.3rem);
  -webkit-text-stroke-width: 4px;
  margin-bottom: clamp(var(--s3), 2.4vh, var(--s5));
}

.hero__copy .lede {
  margin-bottom: var(--s5);
}

.hero__copy .lede strong {
  color: #0b2f52;
}

.hero__facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  list-style: none;
  margin: clamp(var(--s3), 2.4vh, var(--s5)) 0 0;
  padding: 0;
}

.hero__facts .chip {
  background: rgba(255, 255, 255, 0.86);
  color: var(--ink-card-title);
}

/* --- The assembling puzzle ---------------------------------------------- */

.hero__stage {
  position: relative;
  display: flex;
  justify-content: center;
}

.hero-puzzle {
  width: min(100%, 520px);
  filter: drop-shadow(0 24px 30px rgba(9, 52, 96, 0.3));
}

.hero-puzzle__svg {
  width: 100%;
  height: auto;
  overflow: visible;
}

/*
 * Each piece flies in from off the nearest edge, lands, and flashes once as
 * it seats - the Bloom class, on a per-piece scale. home.js sets --from-x,
 * --from-y, --rot and --delay per piece; the keyframes are shared.
 */
.hero-piece {
  opacity: 0;
  transform: translate(var(--from-x, 0), var(--from-y, 0)) rotate(var(--rot, 0deg));
}

[data-play='true'] .hero-piece {
  animation: piece-snap 720ms var(--ease-out) both;
  animation-delay: var(--delay, 0ms);
}

@keyframes piece-snap {
  0% {
    opacity: 0;
    transform: translate(var(--from-x, 0), var(--from-y, 0)) rotate(var(--rot, 0deg)) scale(1.08);
  }
  55% {
    opacity: 1;
  }
  78% {
    transform: translate(0, 0) rotate(0deg) scale(1.03);
    filter: brightness(1.45);
  }
  90% {
    transform: translate(0, 0) rotate(0deg) scale(0.985);
  }
  100% {
    opacity: 1;
    transform: none;
    filter: brightness(1);
  }
}

/*
 * Reduced motion: the hero must render FINISHED, not empty.
 *
 * .hero-piece rests at opacity 0 and only becomes visible through the
 * assembly animation, which home.js does not start when the visitor asked
 * for reduced motion - so without this the whole hero puzzle is invisible
 * for exactly the people who opted out of animation. Cancelling the
 * animation is not enough; the resting state has to be corrected too.
 */
@media (prefers-reduced-motion: reduce) {
  .hero-piece {
    opacity: 1;
    transform: none;
    animation: none;
  }
}

.hero__kip {
  position: absolute;
  right: -7%;
  bottom: -26%;
  width: clamp(110px, 16vw, 160px);
  filter: drop-shadow(0 12px 14px rgba(9, 52, 96, 0.34));
  animation-delay: 1.2s;
}

/* --- Loose pieces drifting behind everything ---------------------------- */

.drift-field {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

.drift-piece {
  position: absolute;
  opacity: 0.72;
  filter: drop-shadow(0 6px 8px rgba(9, 52, 96, 0.22));
}

/* On a phone the hero copy fills the width, so a full field of drifting
   pieces lands on top of the text instead of around it. Keep the few that
   sit clear of the column. */
@media (max-width: 700px) {
  .drift-piece:nth-child(even) {
    display: none;
  }

  .drift-piece {
    opacity: 0.5;
  }
}

/* --- The workbench the hero sits on ------------------------------------- */

.workbench {
  position: absolute;
  inset: auto 0 0;
  z-index: -1;
  line-height: 0;
}

.workbench img {
  width: 100%;
  height: clamp(96px, 13vw, 160px);
  object-fit: cover;
  object-position: center 30%;
}

.workbench::after {
  content: '';
  position: absolute;
  inset: 0 0 auto;
  height: 40px;
  background: linear-gradient(rgba(166, 219, 255, 0.9), rgba(166, 219, 255, 0));
}

@media (max-width: 860px) {
  .hero__inner {
    grid-template-columns: 1fr;
    text-align: center;
  }

  .hero__copy .lede,
  .hero__facts {
    margin-inline: auto;
    justify-content: center;
  }

  .hero .stores {
    justify-content: center;
  }

  .hero__kip {
    right: 2%;
    bottom: -8%;
  }
}


/*
 * Fit the hero to the screen.
 *
 * Sized by width alone it ran taller than a laptop viewport, so the workbench
 * band at its foot was cut off by the fold and the hero could never be seen
 * whole. From the two-column breakpoint up it becomes a deliberate
 * full-viewport hero instead: exactly the height left under the sticky
 * header, with the type scaled by viewport HEIGHT as well as width so it
 * still fits on a short laptop screen.
 *
 * dvh, not vh: on mobile browsers vh is the tallest possible viewport and
 * ignores the retracting address bar, which would reintroduce the same crop.
 */
@media (min-width: 861px) {
  .hero {
    min-height: calc(100dvh - var(--header-h));
    display: flex;
    flex-direction: column;
    justify-content: center;
  }

  .hero__wordmark {
    /* 1270x702 art, so 34vh of width is ~19vh of height. */
    width: min(420px, 34vh);
  }

  .hero__title {
    font-size: min(3.3rem, 5vw, 7.2vh);
  }

  .hero__copy .lede {
    font-size: min(1.25rem, 2.1vh);
  }

  .hero__inner {
    /* Leave room for the workbench, which is absolutely positioned at the
       bottom of this section and would otherwise sit on top of the chips. */
    padding-bottom: clamp(100px, 17vh, 210px);
  }
}

@media (min-width: 861px) and (max-height: 790px) {
  .hero__wordmark {
    width: min(340px, 27vh);
  }

  .hero__title {
    font-size: min(2.6rem, 4.4vw, 6.2vh);
    -webkit-text-stroke-width: 3px;
  }

  .hero__copy .lede {
    font-size: min(1.05rem, 1.95vh);
  }

  .hero__facts .chip {
    font-size: 0.78rem;
    padding: 5px var(--s3);
  }

  .hero__inner {
    padding-bottom: clamp(78px, 13vh, 150px);
  }

  .workbench img {
    height: clamp(72px, 11vh, 130px);
  }
}

/*
 * Landscape phone. The viewport is wide enough to trip the stacked layout
 * above but only ~390px tall, which puts the wordmark alone on the whole
 * screen and pushes everything else below the fold. Go back to two columns
 * and scale the hero to the height rather than the width.
 */
@media (orientation: landscape) and (max-height: 540px) {
  .hero__inner {
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    text-align: left;
    padding-bottom: clamp(40px, 9vh, 90px);
  }

  .hero__copy .lede,
  .hero__facts,
  .hero .stores {
    margin-inline: 0;
    justify-content: flex-start;
  }

  .hero__wordmark {
    width: min(230px, 28vw);
    margin-bottom: var(--s3);
  }

  .hero__title {
    font-size: clamp(1.25rem, 3.2vw, 1.9rem);
    -webkit-text-stroke-width: 3px;
    margin-bottom: var(--s3);
  }

  .hero__copy .lede {
    font-size: 0.95rem;
    margin-bottom: var(--s3);
  }

  /* The fact chips are a nice-to-have; the store buttons are not. */
  .hero__facts {
    display: none;
  }

  .workbench img {
    height: clamp(56px, 14vh, 100px);
  }

  .section {
    padding-block: clamp(40px, 9vh, 80px);
  }

  /* The sticky header is ~90px of a 390px-tall screen; trim it back. */
  .site-header__inner {
    min-height: 52px;
  }

  .site-header__mark img {
    width: 100px;
  }

  .hero {
    padding-top: var(--s3);
  }
}


/* ==========================================================================
   Shared section furniture
   ========================================================================== */

.section-head {
  margin-bottom: clamp(32px, 5vw, 56px);
}

.section-head .plaque {
  margin-bottom: var(--s5);
}

.grid--3 {
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}

.grid--4 {
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

.feature-grid {
  list-style: none;
  margin: 0;
  padding: 0;
}

.feature-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  margin-bottom: var(--s4);
  border-radius: 18px;
  color: #fff;
  background: var(--accent, var(--play-blue));
  box-shadow: 0 5px 0 rgba(9, 64, 124, 0.28);
}

.feature-icon svg {
  width: 28px;
  height: 28px;
}

.tick-list {
  list-style: none;
  margin: var(--s5) 0 0;
  padding: 0;
  display: grid;
  gap: var(--s3);
}

.tick-list li {
  position: relative;
  padding-left: 34px;
  color: var(--ink-card-body);
}

.tick-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 3px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--leaf)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 13l4 4 10-10'/%3E%3C/svg%3E")
    center / 15px no-repeat;
}

/* ==========================================================================
   Worlds rail
   ========================================================================== */

.world-rail {
  display: flex;
  gap: var(--s5);
  list-style: none;
  margin: 0 0 var(--s7);
  padding: var(--s2) var(--gutter) var(--s6);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}

.world {
  flex: 0 0 auto;
  scroll-snap-align: center;
}

.world__card {
  display: block;
  position: relative;
  width: clamp(210px, 62vw, 300px);
  border-radius: 26px;
  overflow: hidden;
  text-decoration: none;
  background: var(--card-cream);
  box-shadow: 0 8px 0 var(--card-bevel-hero), 0 22px 36px var(--card-shadow);
  transition: transform var(--react-up) var(--ease-out), box-shadow var(--react-up) var(--ease-out);
}

.world__card img {
  aspect-ratio: 9 / 16;
  object-fit: cover;
  width: 100%;
  /* The art drifts inside its own frame as the rail scrolls past. The scale
     gives it headroom so the drift never exposes an edge, and the clamp caps
     it well inside that headroom. --parallax is set by site.js, and is 0 when
     the visitor asked for reduced motion. */
  transform: translate3d(0, clamp(-34px, var(--parallax, 0px), 34px), 0) scale(1.08);
}

@media (hover: hover) {
  .world__card:hover {
    transform: translateY(-6px);
    box-shadow: 0 14px 0 var(--card-bevel-hero), 0 30px 44px var(--card-shadow);
  }
}

.world__plate {
  position: absolute;
  inset: auto var(--s3) var(--s3);
  display: grid;
  gap: 2px;
  padding: var(--s3) var(--s4);
  border-radius: 18px;
  background: rgba(255, 253, 246, 0.94);
  box-shadow: 0 4px 0 var(--card-bevel);
}

.world__n {
  font-family: 'Baloo 2', sans-serif;
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  color: var(--ink-card-muted);
}

.world__plate strong {
  font-family: 'Baloo 2', sans-serif;
  font-size: 1.2rem;
  color: var(--ink-card-title);
  line-height: 1.15;
}

.world__plate em {
  font-style: normal;
  font-size: 0.9rem;
  color: var(--ink-card-meta);
}

/* ==========================================================================
   Difficulty ladder
   ========================================================================== */

.ladder {
  display: grid;
  gap: clamp(24px, 4vw, 48px);
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  align-items: center;
}

@media (max-width: 860px) {
  .ladder {
    grid-template-columns: 1fr;
  }
}

.ladder__count {
  font-family: 'Baloo 2', sans-serif;
  font-weight: 800;
  font-size: 1.3rem;
  color: var(--play-blue);
  margin-bottom: var(--s1);
}

.ladder__note {
  color: var(--ink-card-muted);
  margin-bottom: 0;
}

.ladder__board {
  background: var(--card-sunken);
  border-radius: var(--r-tile);
  padding: var(--s4);
  box-shadow: inset 0 3px 0 rgba(15, 61, 107, 0.08);
}

.ladder__svg {
  width: 100%;
  height: auto;
  overflow: visible;
}

/* Pieces fade in one after another when the grid changes, so switching tier
   reads as a puzzle being cut rather than a picture being swapped. */
.ladder__board:not([data-dense='true']) .ladder__svg path {
  /* fill-box + center origin so each piece scales about ITSELF; the default
     view-box origin would scale every piece toward the board's corner. */
  transform-box: fill-box;
  transform-origin: center;
  animation: settle-pop 260ms var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * 9ms);
}

.ladder__tiers {
  display: grid;
  /* Three across on the narrowest phones: at 320px four columns leave ~54px
     per tile and the longest labels ("Advanced", "Medium") spill out of
     their tiles. Four fits from 360px up. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s2);
  margin-top: var(--s4);
}

@media (min-width: 360px) {
  .ladder__tiers {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.ladder__tier {
  display: grid;
  gap: 2px;
  place-items: center;
  min-height: 56px;
  padding: var(--s2);
  border: 0;
  border-radius: 14px;
  cursor: pointer;
  background: var(--card);
  color: var(--ink-card-meta);
  box-shadow: 0 3px 0 var(--card-bevel);
  transition: background var(--react-up) var(--ease-out), color var(--react-up) var(--ease-out),
    box-shadow var(--react-up) var(--ease-out), transform var(--react-down) var(--ease-out);
}

.ladder__tier-label {
  font-family: 'Baloo 2', sans-serif;
  font-weight: 700;
  font-size: clamp(0.8rem, 2.4vw, 0.9rem);
  line-height: 1;
  white-space: nowrap;
}

.ladder__tier-count {
  font-size: 0.78rem;
  opacity: 0.75;
}

.ladder__tier[aria-selected='true'] {
  background: linear-gradient(var(--gummy-blue-top), var(--gummy-blue-bottom));
  color: #fff;
  box-shadow: 0 4px 0 var(--gummy-blue-lift), inset 0 -3px 0 var(--gummy-blue-inset);
}

.ladder__tier:active {
  transform: translateY(3px);
  box-shadow: 0 0 0 var(--card-bevel);
}

/* ==========================================================================
   Co-op
   ========================================================================== */

.section--coop .coop {
  display: grid;
  gap: clamp(28px, 5vw, 64px);
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
}

@media (max-width: 860px) {
  .section--coop .coop {
    grid-template-columns: 1fr;
  }
}

.coop__scene {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(8px, 3vw, 28px);
  padding-block: var(--s6);
}

.phone {
  position: relative;
  /* The phones are rotated, so their bounding boxes are wider than their
     layout width - at 320px the un-narrowed pair pushed 4px past the page. */
  width: clamp(84px, 20vw, 150px);
  padding: 10px 10px 20px;
  border-radius: 22px;
  background: #10243a;
  box-shadow: 0 8px 0 #061524, 0 20px 30px rgba(6, 21, 36, 0.32);
}

.phone--host {
  transform: rotate(-5deg);
}

.phone--guest {
  transform: rotate(5deg);
}

.phone__screen {
  border-radius: 14px;
  overflow: hidden;
  aspect-ratio: 3 / 4;
}

.phone__screen img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.phone__label {
  position: absolute;
  top: -14px;
  left: 50%;
  transform: translateX(-50%);
  padding: 3px 12px;
  border-radius: var(--r-pill);
  background: var(--coop-0);
  color: #fff;
  font-family: 'Baloo 2', sans-serif;
  font-weight: 700;
  font-size: 0.72rem;
  white-space: nowrap;
}

.coop__code {
  display: grid;
  gap: 2px;
  place-items: center;
  padding: var(--s3) var(--s4);
  border-radius: 16px;
  background: var(--card-cream);
  box-shadow: 0 5px 0 var(--card-bevel);
  z-index: 1;
}

.coop__code-label {
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-card-muted);
}

.coop__code-value {
  font-family: 'Baloo 2', sans-serif;
  font-size: clamp(1.1rem, 2.6vw, 1.5rem);
  color: var(--coop-link-ink);
  letter-spacing: 0.04em;
}

/* ==========================================================================
   Pictures
   ========================================================================== */

/* Explicit columns, not auto-fit: at 390px a 180px minimum collapses to one
   column and turns eight pictures into a 2600px-tall scroll. */
.picture-wall {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s3);
  list-style: none;
  margin: 0;
  padding: 0;
}

@media (min-width: 760px) {
  .picture-wall {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--s4);
  }
}

.picture-wall img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--r-thumb);
  box-shadow: 0 5px 0 var(--card-bevel), 0 12px 20px var(--card-shadow);
}

/* Every tile keeps the same 4:3 crop. A mixed-aspect "masonry" here just
   produced ragged rows at the widths this grid actually lands on. */

/* ==========================================================================
   Your photos
   ========================================================================== */

.photos {
  display: grid;
  gap: clamp(20px, 4vw, 52px);
  grid-template-columns: minmax(0, 0.6fr) minmax(0, 1fr);
  align-items: center;
}

.photos__art {
  display: flex;
  justify-content: center;
}

.photos__art img {
  width: clamp(150px, 28vw, 300px);
  filter: drop-shadow(0 14px 18px rgba(9, 52, 96, 0.3));
}

@media (max-width: 800px) {
  .photos {
    grid-template-columns: 1fr;
  }
}

/* ==========================================================================
   Pals
   ========================================================================== */

.pal-grid {
  display: grid;
  /* Explicit column counts rather than auto-fit: the home page shows exactly
     six Pals, and auto-fit lands on five-across at common desktop widths,
     orphaning the sixth on a row of its own. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s4);
  list-style: none;
  margin: 0 0 var(--s7);
  padding: 0;
}

@media (min-width: 620px) {
  .pal-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (min-width: 1000px) {
  .pal-grid {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
}

/* A grid item defaults to min-width:auto, so a card whose content has a wide
   min-content size pushes past its own track and takes the page with it. The
   roster's two-column phone layout hits exactly that. */
.pal {
  min-width: 0;
}

.pal .card {
  height: 100%;
  display: grid;
  align-content: start;
  gap: var(--s1);
  text-align: center;
  border-top: 5px solid var(--accent, var(--play-blue));
}

.pal__art {
  display: flex;
  justify-content: center;
  margin-bottom: var(--s2);
}

.pal__art img {
  width: clamp(88px, 22vw, 124px);
  filter: drop-shadow(0 8px 10px rgba(9, 52, 96, 0.24));
}

.pal__name {
  font-size: 1.25rem;
  margin: 0;
}

.pal__role {
  margin: 0;
  font-family: 'Baloo 2', sans-serif;
  font-weight: 600;
  font-size: 0.82rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-card-muted);
}

.pal__perk {
  margin: var(--s2) 0 0;
  font-size: 0.92rem;
  color: var(--ink-card-body);
  /* Perk copy contains long hyphenated compounds ("picture-preview",
     "auto-place"); in a 150px-wide card those have to be allowed to break. */
  overflow-wrap: anywhere;
}

.pal__price {
  margin: var(--s3) 0 0;
  display: flex;
  justify-content: center;
  gap: var(--s2);
}

/* ==========================================================================
   Progress + final CTA
   ========================================================================== */

.stat-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  text-align: center;
}

.stat__n {
  display: block;
  font-family: 'Baloo 2', sans-serif;
  font-size: 2.6rem;
  line-height: 1;
  color: var(--play-blue);
}

.stat__label {
  display: block;
  margin-top: var(--s2);
  font-size: 0.92rem;
  color: var(--ink-card-muted);
}

.cta-final {
  padding-bottom: var(--s8);
}

.cta-final__kip {
  width: clamp(130px, 24vw, 200px);
  margin: 0 auto var(--s4);
  filter: drop-shadow(0 14px 16px rgba(9, 52, 96, 0.3));
}

/* The final CTA lands on the palest end of the sky gradient (#EEF9FF), where
   the default white-filled display title all but disappears. This is the
   game's own win-screen treatment - gold fill, saturated blue stroke - which
   is built for exactly that bright-background case. */
.cta-final h2 {
  font-size: clamp(2rem, 5.2vw, 3.2rem);
  margin-bottom: var(--s4);
}

.cta-final .lede {
  color: #14456f;
}

.stores--center {
  justify-content: center;
  margin-top: var(--s5);
}

/* ==========================================================================
   Hero kicker - the one line that says what this is, in search-engine words.
   Small text on the sky, so it gets a surface (see .panel in components.css).
   ========================================================================== */

.hero__kicker {
  display: inline-block;
  margin: 0 0 var(--s3);
  padding: 5px var(--s4);
  border-radius: var(--r-pill);
  background: rgba(255, 253, 246, 0.94);
  box-shadow: 0 3px 0 rgba(196, 214, 228, 0.7);
  font-family: 'Baloo 2', sans-serif;
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: 0.03em;
  color: var(--ink-card-title);
}

/* ==========================================================================
   See it in action: trailer + screenshot rail
   ========================================================================== */

.trailer {
  max-width: 960px;
  margin: var(--s6) auto 0;
  padding: clamp(8px, 1.4vw, 14px);
}

/* Click-to-play poster (assets/js/trailer.js swaps it for the player). */
.yt,
.yt__frame {
  display: block;
  position: relative;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  border: 0;
  border-radius: 18px;
  overflow: hidden;
  background: #10243a;
}

.yt {
  text-decoration: none;
  isolation: isolate;
}

.yt__poster {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 600ms var(--ease-out), filter var(--react-up) var(--ease-out);
}

/* A soft scrim at the bottom so the label always has something to sit on. */
.yt::after {
  content: '';
  position: absolute;
  inset: 45% 0 0;
  background: linear-gradient(transparent, rgba(6, 21, 36, 0.55));
  pointer-events: none;
}

.yt__play {
  position: absolute;
  z-index: 1;
  top: 50%;
  left: 50%;
  display: grid;
  place-items: center;
  width: clamp(72px, 11vw, 104px);
  aspect-ratio: 1;
  border-radius: 50%;
  translate: -50% -50%;
  background: linear-gradient(var(--gem-gold-0), var(--gem-gold-1));
  box-shadow:
    0 7px 0 var(--gem-shadow),
    0 18px 34px rgba(6, 21, 36, 0.35),
    inset 0 -5px 0 var(--gummy-gold-inset);
  transition: transform var(--react-up) var(--ease-gummy);
}

/* A slow ring pulses out of the button so it reads as "press me" before the
   pointer ever arrives. Reduced motion keeps the ring, standing still. */
.yt__play::before {
  content: '';
  position: absolute;
  inset: -10px;
  border-radius: 50%;
  border: 4px solid rgba(255, 216, 107, 0.75);
  animation: yt-pulse 2.4s var(--ease-out) infinite;
}

@keyframes yt-pulse {
  0% { transform: scale(0.92); opacity: 0.9; }
  70%, 100% { transform: scale(1.28); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .yt__play::before {
    animation: none;
    opacity: 0.6;
  }
}

.yt__play svg {
  width: 44%;
  height: 44%;
  margin-left: 8%;
  fill: var(--gem-ink);
}

.yt__label {
  position: absolute;
  z-index: 1;
  left: clamp(12px, 2.4vw, 24px);
  bottom: clamp(12px, 2.4vw, 22px);
  display: grid;
  gap: 2px;
  padding: var(--s2) var(--s4);
  border-radius: var(--r-tile);
  background: rgba(255, 253, 246, 0.95);
  box-shadow: 0 4px 0 rgba(6, 21, 36, 0.25);
  color: var(--ink-card-body);
  font-size: 0.85rem;
  line-height: 1.3;
}

.yt__label strong {
  font-family: 'Baloo 2', sans-serif;
  font-size: 1.1rem;
  color: var(--ink-card-title);
}

@media (hover: hover) {
  .yt:hover .yt__poster {
    transform: scale(1.03);
    filter: saturate(1.08);
  }

  .yt:hover .yt__play {
    transform: scale(1.08);
  }
}

.yt:focus-visible {
  outline: 4px solid var(--sun);
  outline-offset: 4px;
}

.yt:active .yt__play {
  transform: scale(0.96);
}

.screen-rail {
  display: flex;
  gap: clamp(16px, 2.4vw, 28px);
  list-style: none;
  margin: var(--s7) 0 0;
  padding: var(--s3) var(--gutter) var(--s6);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}

.screen-rail > li {
  flex: 0 0 auto;
  scroll-snap-align: center;
}

/* Auto margins centre the row when it fits and fall back to 0 when it
   overflows - unlike justify-content:center, which would clip the first
   phone off the scrollable start. */
.screen-rail > li:first-child {
  margin-left: auto;
}

.screen-rail > li:last-child {
  margin-right: auto;
}

.device {
  margin: 0;
  width: clamp(196px, 56vw, 250px);
}

.device img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 9 / 16;
  object-fit: cover;
  border: 8px solid #10243a;
  border-radius: 30px;
  background: #10243a;
  box-shadow: 0 8px 0 #061524, 0 22px 36px var(--card-shadow);
}

.device figcaption {
  display: block;
  width: fit-content;
  margin: var(--s4) auto 0;
  padding: 6px var(--s4);
  border-radius: var(--r-pill);
  background: rgba(255, 253, 246, 0.94);
  box-shadow: 0 3px 0 rgba(196, 214, 228, 0.7);
  font-family: 'Baloo 2', sans-serif;
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--ink-card-title);
  text-align: center;
}

/* On a phone the trailer is ~190px tall: shrink the button and fold the
   label onto one line so neither sits on the other. */
@media (max-width: 560px) {
  .yt__play {
    width: 60px;
  }

  .yt__play::before {
    inset: -7px;
    border-width: 3px;
  }

  .yt__label {
    display: flex;
    align-items: baseline;
    gap: var(--s2);
    padding: 4px var(--s3);
    border-radius: var(--r-pill);
    font-size: 0.78rem;
  }

  .yt__label strong {
    font-size: 0.95rem;
  }
}
