/* Shared visual layer for service-page heroes. The page keeps its own copy and
   controls while the service planet follows the same scroll timeline as home. */
.service-hero .service-rail.rail-slider {
  isolation: isolate;
}

.service-hero .service-rail.rail-slider::before {
  content: '';
  position: absolute;
  z-index: 0;
  left: 0;
  top: var(--rail-indicator-y, 6px);
  width: var(--rail-indicator-width, 0px);
  height: var(--rail-indicator-height, 44px);
  border-radius: 12px;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(130deg, #ffffff23, #ffffff09);
  box-shadow: inset 0 1px 0 #ffffff40, 0 3px 12px #0002;
  transform: translate3d(var(--rail-indicator-x, 6px), 0, 0);
  transition:
    transform .48s cubic-bezier(.22, .8, .22, 1),
    width .48s cubic-bezier(.22, .8, .22, 1),
    height .3s ease,
    top .3s ease,
    opacity .18s ease;
  will-change: transform, width;
}

.service-hero .service-rail.rail-slider.is-ready::before {
  opacity: 1;
}

.service-hero .service-rail.rail-slider .rail-item {
  z-index: 1;
}

.service-hero .service-rail.rail-slider .rail-item.active,
.service-hero .service-rail.rail-slider .rail-item.active:hover {
  background: transparent;
  box-shadow: none;
}

.service-hero .service-cosmos {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  pointer-events: none;
  isolation: isolate;
  background: #020813;
}

.service-hero .service-cosmos-background {
  position: absolute;
  inset: -3%;
  z-index: 0;
  width: 106%;
  height: 106%;
  object-fit: cover;
  opacity: .96;
  transform: translate3d(calc(var(--p, 0) * -1.5%), calc(var(--p, 0) * .7%), 0) scale(1.025);
}

/* Slide one holds the planet where home leaves it at this service's own stop:
   stage-centred at .86. Home scales its layer about an off-centre origin, so
   --home-ox/--home-oy replay that origin's offset while the planet is up top;
   both fall away as it drops onto the bottom anchor the rest of the timeline
   keeps using, which stays exactly where it was. */
.service-hero .service-planet-stage {
  --planet-edge-x: clamp(48px, 6vw, 96px);
  position: absolute;
  z-index: 2;
  left: 50%;
  top: 50%;
  width: max(100vw, 150svh);
  aspect-ratio: 3 / 2;
  transform:
    translate3d(
      calc(-50% + var(--planet-edge-x) + var(--planet-rise, 1) * var(--home-ox, 0%)),
      calc(-50% + var(--planet-drop, 0) * 72svh + var(--planet-rise, 1) * var(--home-oy, 0%)),
      0
    )
    scale(calc(.86 + var(--planet-drop, 0) * .02));
  transform-origin: 50% 50%;
  will-change: transform;
}

/* Rotation lives on the wrapper so both passes turn around the same disc.
   --planet-zoom rides that same origin, so a page that wants more air around
   the globe shrinks it in place instead of dragging the disc off its anchor
   the way a scale on the stage would. */
.service-hero .service-planet-spin {
  position: absolute;
  inset: 0;
  transform: rotate(calc(var(--p, 0) * -360deg)) scale(var(--planet-zoom, 1));
  transform-origin: var(--planet-cx, 63%) var(--planet-cy, 48%);
  will-change: transform;
}

.service-hero .service-planet {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  backface-visibility: hidden;
}

/* The two passes are different render generations, so their discs do not sit at
   the same place on the canvas. The intro keeps home's raw framing while it is
   the only thing on screen, then drifts onto the parked planet's registration
   across the swap so the two discs coincide by the time they cross. */
.service-hero .service-planet--intro {
  opacity: calc(1 - var(--planet-swap, 0));
  transform:
    translate(
      calc(var(--intro-dx, 0%) * var(--planet-swap, 0)),
      calc(var(--intro-dy, 0%) * var(--planet-swap, 0))
    )
    scale(calc(1 + (var(--intro-scale, 1) - 1) * var(--planet-swap, 0)));
  transform-origin: var(--intro-cx, 63%) var(--intro-cy, 48%);
  will-change: transform, opacity;
}

.service-hero .service-planet--main {
  opacity: var(--planet-swap, 0);
  will-change: opacity;
}

.service-hero .service-rocket-stage {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 3;
  /* The rocket sits above the hero veil, with some softness retained. */
  opacity: .85;
  width: max(100vw, 150svh);
  aspect-ratio: 3 / 2;
  transform: translate3d(-50%, -50%, 0);
  pointer-events: none;
}

.service-hero .service-rocket {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  transform: translate3d(
    calc(var(--rocket-home-x, -10%) + var(--rocket-scroll-x, 0%) + var(--rocket-pointer-x, 0px)),
    calc(12% + var(--rocket-scroll-y, 0%) + var(--rocket-pointer-y, 0px)),
    0
  ) rotate(var(--rocket-pointer-rotate, 0deg)) scale(.4);
  transform-origin: 50% 50%;
  /* Keep the shared rocket readable against the service-page space scenes
     without turning its trail into a bright highlight. */
  filter: brightness(1.12) contrast(1.02);
  will-change: transform;
}

.service-hero .service-cosmos::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg, rgba(2, 8, 19, .78) 0%, rgba(2, 8, 19, .38) 40%, rgba(2, 8, 19, .06) 70%),
    linear-gradient(180deg, rgba(2, 8, 19, .06), transparent 48%, rgba(2, 8, 19, .34));
}

/* The first service slide mirrors the focused, planet-led state on home.
   The existing card becomes available again from step two onward. */
.service-hero.is-service-intro .glass {
  visibility: hidden;
  opacity: 0 !important;
  pointer-events: none;
}

@media (max-width: 680px) {
  /* Pre-script default only -- the hero's inline vars take over on first frame.
     Mobile never opens on the raised planet, so it must not flash there. */
  .service-hero {
    --planet-drop: 1;
    --planet-rise: 0;
    --planet-swap: 1;
  }

  .service-hero .service-planet-stage {
    --planet-edge-x: 24px;
    width: 170vw;
    top: 57%;
    transform:
      translate3d(
        calc(-50% + var(--planet-edge-x) + var(--planet-rise, 1) * var(--home-ox, 0%)),
        calc(-50% + var(--planet-drop, 0) * 66svh + var(--planet-rise, 1) * var(--home-oy, 0%)),
        0
      )
      scale(calc(.80 + var(--planet-drop, 0) * .12));
  }

  .service-hero .service-rocket-stage {
    width: 170vw;
    top: 57%;
    opacity: .72;
  }

  .service-hero .service-rocket {
    transform: translate3d(calc(-8% + var(--rocket-pointer-x, 0px)), calc(3% + var(--rocket-pointer-y, 0px)), 0) rotate(var(--rocket-pointer-rotate, 0deg)) scale(.36);
  }

  .service-hero .service-cosmos::after {
    background:
      linear-gradient(180deg, rgba(2, 8, 19, .18), transparent 40%, rgba(2, 8, 19, .28)),
      linear-gradient(90deg, rgba(2, 8, 19, .24), transparent 70%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .service-hero .service-planet-spin {
    transform: none;
  }

  .service-hero .service-rocket {
    --rocket-pointer-x: 0px !important;
    --rocket-pointer-y: 0px !important;
    --rocket-pointer-rotate: 0deg !important;
  }
}

/* Platform boards. One mock-up per slide: it comes in from the right, parks
   while its slide is on, then keeps travelling left as the next one arrives,
   so the three read as one conveyor rather than three separate fades.

   --reveal (opacity) and --shift (+1 waiting off to the right, 0 parked, -1
   gone to the left) are written per element by the hero script from the same
   scroll progress that drives the phases.

   The layer sits outside .service-cosmos, above the veil: the veil is nearly
   opaque on narrow viewports and would bury the boards there. */
.service-hero .service-boards {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}

.service-hero .hero-board {
  --reveal: 0;
  --shift: 1;
  position: absolute;
  left: var(--board-x, 76%);
  top: var(--board-y, 50%);
  width: var(--board-w, min(clamp(340px, 37vw, 600px), 76svh));
  opacity: var(--reveal);
  transform:
    translate3d(
      calc(-50% + var(--shift) * var(--board-travel, 58%) + var(--pointer-x, 0) * 13px),
      calc(var(--board-anchor, -50%) + var(--pointer-y, 0) * 7px),
      0
    )
    scale(calc(.97 + var(--reveal) * .03));
  will-change: transform, opacity;
  contain: layout style;
}

/* The drift is vertical only -- these are flat UI panels, and a rotation on
   them reads as a tilt rather than as float. */
.service-hero .board-float {
  display: block;
  animation: heroBoardFloat var(--board-float, 15s) ease-in-out infinite;
  animation-delay: var(--board-delay, 0s);
}

.service-hero .hero-board[data-board='meta']   { --board-float: 17s; --board-delay: -5s; }
.service-hero .hero-board[data-board='tiktok'] { --board-float: 13s; --board-delay: -9s; }

.service-hero .hero-board img {
  display: block;
  width: 100%;
  height: auto;
  filter: drop-shadow(0 32px 60px rgba(2, 8, 19, .55));
}

@keyframes heroBoardFloat {
  0%, 100% { transform: translate3d(0, -1.1%, 0); }
  50%      { transform: translate3d(0, 1.3%, 0); }
}

/* Tablet centres the copy on a 680px column and drops the rail right under it,
   so nothing is free beside the text. The board sits on the bottom edge
   instead, capped by height so its top always clears the rail. */
@media (max-width: 1020px) {
  .service-hero .hero-board {
    --board-x: 50%;
    /* 35svh is what keeps the board's top edge below the rail once the pin
       gets short -- the rail stays put while the board would otherwise grow
       into it. */
    --board-w: min(64vw, 35svh);
    --board-anchor: 0%;
    --board-travel: 64%;
    top: auto;
    bottom: 3%;
  }
}

@media (max-width: 680px) {
  .service-hero .hero-board {
    --board-w: min(92vw, 34svh);
  }
}

/* Short landscape leaves no band at all once the copy and the rail have taken
   their room, so the board steps aside instead of crossing them. Portrait
   phones stay short but narrow, and those keep their band. */
@media (max-height: 520px), (min-width: 681px) and (max-width: 1020px) and (max-height: 720px) {
  .service-hero .service-boards {
    display: none;
  }
}

/* Short phones: the rail sits much higher up the pin, so the board shrinks
   again to keep clear of it. */
@media (max-width: 680px) and (max-height: 700px) {
  .service-hero .hero-board {
    --board-w: min(92vw, 26svh);
    bottom: 2%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .service-hero .board-float {
    animation: none;
  }

  .service-hero .hero-board {
    --board-travel: 0%;
  }
}
