/* Homepage: iPhone device frames for the App Store captures, the first-visit loader,
   and the 3D entrance motion. Everything here is decoration: with no JavaScript, or with
   reduced motion, the page renders still and complete. */

/* ---------- iPhone frame ----------
   The captures already carry the status bar and Dynamic Island, so the frame only draws
   the titanium band, the black bezel and the side buttons. */
.iphone {
  --iphone-w: min(300px, 100%);
  position: relative;
  width: var(--iphone-w);
  aspect-ratio: 828 / 1792;
  padding: 3.2%;
  border-radius: 15% / 7%;
  background:
    linear-gradient(145deg, #4a4a4f 0%, #1d1d20 22%, #0d0d0f 50%, #232327 78%, #55555b 100%);
  box-shadow:
    inset 0 0 0 1.5px rgb(255 255 255 / 14%),
    inset 0 0 0 5px #050506,
    0 2px 1px rgb(255 255 255 / 6%),
    0 40px 80px -20px rgb(0 0 0 / 75%),
    0 18px 36px -18px rgb(0 0 0 / 60%);
  transform-style: preserve-3d;
}
.iphone::before,
.iphone::after {
  content: "";
  position: absolute;
  width: 1.1%;
  border-radius: 2px;
  background: linear-gradient(90deg, #2a2a2e, #5a5a60);
}
/* Action button and volume rocker on the left, side button on the right. */
.iphone::before {
  left: -1%;
  top: 17%;
  height: 26%;
  background: linear-gradient(180deg, #4a4a50 0 15%, transparent 15% 30%, #4a4a50 30% 60%, transparent 60% 70%, #4a4a50 70% 100%);
}
.iphone::after {
  right: -1%;
  top: 24%;
  height: 10%;
  background: linear-gradient(270deg, #2a2a2e, #5a5a60);
}
.iphone img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top;
  border-radius: 12.5% / 5.8%;
  background: #0f1230;
}
/* Glass sheen that slides across the screen as the phone turns. */
.iphone .iphone-glare {
  position: absolute;
  inset: 3.2%;
  border-radius: 12.5% / 5.8%;
  pointer-events: none;
  background: linear-gradient(115deg, transparent 35%, rgb(255 255 255 / 9%) 48%, transparent 60%);
  background-size: 250% 100%;
  background-position: var(--glare, 100%) 0;
  mix-blend-mode: screen;
}

/* ---------- Placement ---------- */
/* Turned phones and hinged sections project past the viewport mid-animation; clip
   them so a phone-width visitor never gets a sideways scroll. */
main {
  overflow-x: clip;
}
.iphone-stage {
  perspective: 1600px;
  min-height: 0;
}
.hero-iphone {
  --iphone-w: min(330px, 82vw);
  transform: rotateY(-14deg) rotateX(5deg) rotateZ(1deg);
}
.iphone-stage::after {
  /* Soft gold floor glow under the hero phone. */
  content: "";
  position: absolute;
  left: 50%;
  bottom: -4%;
  width: 70%;
  height: 60px;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at center, rgb(212 175 55 / 22%), transparent 70%);
  filter: blur(8px);
  pointer-events: none;
  z-index: -1;
}
.product-visual {
  perspective: 1400px;
}
.product-visual .iphone {
  --iphone-w: min(280px, 72vw);
  margin-inline: auto;
}
.chapter:nth-child(odd) .product-visual .iphone { transform: rotateY(-10deg) rotateX(3deg); }
.chapter:nth-child(even) .product-visual .iphone { transform: rotateY(10deg) rotateX(3deg); }

/* ---------- Hero desktop downloads ---------- */
.hero-desktop {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-top: 26px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
  max-width: 560px;
}
.hero-desktop-label {
  font-size: 0.7rem;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--stone);
  font-weight: 700;
  margin-right: 4px;
}
.hero-desktop a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 0 14px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--carbon);
  color: var(--ivory);
  font-size: 0.84rem;
  font-weight: 600;
  transition: border-color 200ms ease, color 200ms ease;
}
.hero-desktop a:hover { border-color: var(--gold); color: var(--lit); }
.hero-desktop img { width: 16px; height: 16px; }
.hero-desktop a.hero-desktop-more {
  border: 0;
  background: none;
  padding: 0 4px;
  color: var(--lit);
}

/* ---------- Atlas orbit ----------
   The still stays underneath; the slow orbit fades in over it once it is playing. */
.atlas-media {
  position: relative;
  display: block;
}
.atlas-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  opacity: 0;
  transition: opacity 900ms ease;
  pointer-events: none;
}
.atlas-video.is-playing { opacity: 1; }

/* ---------- First-visit loader ----------
   Shown only when the head script adds .is-loading, so it never traps a no-JS visitor. */
.site-loader { display: none; }
html.is-loading .site-loader,
html.is-leaving .site-loader {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  background:
    radial-gradient(circle at 50% 45%, rgb(212 175 55 / 10%), transparent 40%),
    var(--obsidian);
  perspective: 900px;
}
html.is-loading { overflow: hidden; }
.loader-inner {
  display: grid;
  justify-items: center;
  gap: 26px;
}
.loader-tile {
  position: relative;
  width: 84px;
  height: 84px;
  transform-style: preserve-3d;
  animation: loader-turn 2.4s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}
.loader-tile img,
.loader-tile span {
  position: absolute;
  inset: 0;
  border-radius: 20px;
  backface-visibility: hidden;
}
.loader-tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  box-shadow: 0 0 0 1px rgb(212 175 55 / 55%), 0 18px 40px rgb(0 0 0 / 60%);
}
/* The back face, so the turn reads as a solid tile rather than a flat card. */
.loader-tile span {
  transform: rotateY(180deg);
  background: linear-gradient(145deg, #2a2410, var(--carbon));
  box-shadow: 0 0 0 1px rgb(212 175 55 / 55%);
}
.loader-tile::after {
  content: "";
  position: absolute;
  left: 8%;
  right: 8%;
  bottom: -26px;
  height: 10px;
  border-radius: 50%;
  background: rgb(0 0 0 / 55%);
  filter: blur(6px);
  transform: translateZ(-1px) rotateX(90deg);
}
.loader-word {
  font: 600 0.82rem var(--serif);
  letter-spacing: 0.32em;
  color: var(--gold);
  padding-left: 0.32em;
}
.loader-bar {
  width: 120px;
  height: 2px;
  background: var(--border);
  overflow: hidden;
  border-radius: 2px;
}
.loader-bar i {
  display: block;
  width: 40%;
  height: 100%;
  background: linear-gradient(90deg, transparent, var(--lit), transparent);
  animation: loader-sweep 1.1s ease-in-out infinite;
}
html.is-leaving .site-loader {
  animation: loader-out 520ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
  pointer-events: none;
}
html.is-leaving .loader-inner {
  animation: loader-inner-out 520ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

@keyframes loader-turn {
  0% { transform: rotateX(12deg) rotateY(0deg); }
  45%, 50% { transform: rotateX(12deg) rotateY(180deg); }
  95%, 100% { transform: rotateX(12deg) rotateY(360deg); }
}
@keyframes loader-sweep {
  from { transform: translateX(-100%); }
  to { transform: translateX(250%); }
}
@keyframes loader-out {
  to { opacity: 0; visibility: hidden; }
}
@keyframes loader-inner-out {
  to { transform: translateZ(180px); opacity: 0; }
}

/* ---------- Entrance motion ----------
   The head script sets .motion-on before first paint when motion is allowed; the hero
   entrance waits until .is-loading is gone, so it plays as the loader leaves. */
html.motion-on:not(.is-loading) .hero-grid > div:first-child > * {
  animation: hero-rise 900ms cubic-bezier(0.22, 1, 0.36, 1) both;
}
html.motion-on:not(.is-loading) .hero-grid > div:first-child > :nth-child(2) { animation-delay: 60ms; }
html.motion-on:not(.is-loading) .hero-grid > div:first-child > :nth-child(3) { animation-delay: 110ms; }
html.motion-on:not(.is-loading) .hero-grid > div:first-child > :nth-child(4) { animation-delay: 160ms; }
html.motion-on:not(.is-loading) .hero-grid > div:first-child > :nth-child(5) { animation-delay: 220ms; }
html.motion-on:not(.is-loading) .hero-grid > div:first-child > :nth-child(n + 6) { animation-delay: 280ms; }
html.motion-on:not(.is-loading) .hero-iphone {
  animation: phone-arrive 1300ms cubic-bezier(0.16, 1, 0.3, 1) 120ms both;
}
html.motion-on:not(.is-loading) .hero-iphone .iphone-glare {
  animation: glare-pass 1500ms cubic-bezier(0.16, 1, 0.3, 1) 300ms both;
}
/* Pointer tilt takes over from the arrival pose once the entrance has finished. */
html.motion-on .hero-iphone.is-tilting {
  animation: none;
  transform: rotateY(calc(-14deg + var(--tilt-y, 0deg))) rotateX(calc(5deg + var(--tilt-x, 0deg))) rotateZ(1deg);
  transition: transform 500ms cubic-bezier(0.22, 1, 0.36, 1);
}
html.motion-on .hero-iphone.is-tilting .iphone-glare {
  animation: none;
  transition: background-position 500ms cubic-bezier(0.22, 1, 0.36, 1);
}
/* Under the loader, hold the hero at its starting frame so the entrance plays on reveal. */
html.is-loading .hero-grid > div:first-child > *,
html.is-loading .hero-iphone { opacity: 0; }

/* Sections settle in with a slight hinge toward the reader instead of a flat fade-up. */
html.motion-on .reveal {
  opacity: 0;
  transform: perspective(1200px) translateY(36px) rotateX(7deg);
  transform-origin: 50% 0;
  transition:
    opacity 800ms cubic-bezier(0.22, 1, 0.36, 1),
    transform 1000ms cubic-bezier(0.22, 1, 0.36, 1);
}
html.motion-on .reveal.visible {
  opacity: 1;
  transform: none;
}
html.motion-on .product-visual .iphone {
  transition: transform 1300ms cubic-bezier(0.16, 1, 0.3, 1) 150ms, opacity 900ms ease 150ms;
}
html.motion-on .chapter:not(.visible) .product-visual .iphone {
  opacity: 0;
  transform: rotateY(-38deg) rotateX(14deg) translateZ(-160px);
}
html.motion-on .chapter:nth-child(even):not(.visible) .product-visual .iphone {
  transform: rotateY(38deg) rotateX(14deg) translateZ(-160px);
}

@keyframes hero-rise {
  from { opacity: 0; transform: translateY(22px); filter: blur(4px); }
  to { opacity: 1; transform: none; filter: none; }
}
@keyframes phone-arrive {
  from {
    opacity: 0;
    transform: translateY(60px) translateZ(-260px) rotateY(-42deg) rotateX(18deg) rotateZ(-4deg);
  }
  to {
    opacity: 1;
    transform: rotateY(-14deg) rotateX(5deg) rotateZ(1deg);
  }
}
@keyframes glare-pass {
  from { background-position: 0% 0; }
  to { background-position: 100% 0; }
}

@media (max-width: 850px) {
  .hero-iphone { --iphone-w: min(300px, 74vw); transform: rotateY(-8deg) rotateX(4deg); }
  @keyframes phone-arrive {
    from { opacity: 0; transform: translateY(50px) translateZ(-200px) rotateY(-30deg) rotateX(16deg); }
    to { opacity: 1; transform: rotateY(-8deg) rotateX(4deg); }
  }
  .chapter:nth-child(odd) .product-visual .iphone,
  .chapter:nth-child(even) .product-visual .iphone { transform: rotateY(-6deg) rotateX(3deg); }
  html.motion-on .chapter:nth-child(even):not(.visible) .product-visual .iphone {
    transform: rotateY(-30deg) rotateX(14deg) translateZ(-160px);
  }
}

@media (prefers-reduced-motion: reduce) {
  html.is-loading .site-loader,
  html.is-leaving .site-loader { display: none; }
  html.is-loading { overflow: auto; }
  html.motion-on:not(.is-loading) .hero-grid > div:first-child > *,
  html.motion-on:not(.is-loading) .hero-iphone,
  html.motion-on:not(.is-loading) .hero-iphone .iphone-glare { animation: none; }
  html.motion-on .reveal,
  html.motion-on .chapter:not(.visible) .product-visual .iphone {
    opacity: 1;
    transform: none;
    transition: none;
  }
}
