/* ══════════════════════════════════════════════════════════════════════
   THE ORBIT OPENING  ·  service pages (orbit.js)

   The page opens on its own title with the NAOU mark beside it, made of
   dust. Scrolling bursts the mark in a flash and a ring of light, the dust
   gathers into a column, and the page's projects orbit it on glass slabs
   while the camera goes down. Then the section lets go and the page
   carries on as before.

   Shot like a film: the dust glows and goes out of focus away from the
   focal plane, the slabs have thickness and catch the column's light,
   distant slabs soften, light falls in beams from above, and soft lights
   hang close to the lens. One sticky stage inside a tall section.

   Reduced motion, no WebGL and no script all get the still layout at the
   bottom of this file: the same title, the same slabs in a row.
   ══════════════════════════════════════════════════════════════════════ */

.orbit {
  /* dark in both themes, like the video hero: dust only glows on dark */
  --band-bg: #0b0909;
  --band-fg: #ffffff;
  --band-fg-mute: rgba(255, 255, 255, 0.68);
  --band-line: rgba(255, 255, 255, 0.16);
  --band-orange: var(--orange);
  --on-dark: var(--band-fg);
  --on-dark-mute: var(--band-fg-mute);
  --line-dark: var(--band-line);
  --orange-text: var(--band-orange);

  /* written by orbit.js */
  --go: 0.22;
  --gb: 0.3;
  --vel: 0;

  position: relative;
  background: var(--band-bg);
  color: var(--band-fg);
}

.orbit__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  height: var(--orbit-h, 100svh);
  overflow: hidden;
}

/* everything the camera sees; it leans into the turns and shakes on the
   burst as one piece, scaled a touch so the leaning never shows a corner */
.orbit__world {
  position: absolute;
  inset: 0;
  transform-origin: 50% var(--orbit-cy, 50%);
}

/* the room: the brand's two lights, never a flat black */
.orbit__ground {
  position: absolute;
  inset: -10%;
  pointer-events: none;
  background:
    radial-gradient(60% 55% at 86% 8%, rgba(255, 103, 0, var(--go)), transparent 70%),
    radial-gradient(55% 60% at 6% 96%, rgba(7, 29, 209, var(--gb)), transparent 70%),
    radial-gradient(120% 90% at 50% 50%, #120e0e 0%, #0b0909 62%, #060505 100%);
}

/* light falling from above, through haze */
.orbit__beams {
  position: absolute;
  inset: -20% -10% 0;
  z-index: 5;
  pointer-events: none;
}

/* each beam is soft at every edge by its own gradient: no blur filter and
   no blend mode, which a phone had to redraw on every frame */
.orbit__beams i {
  position: absolute;
  top: -8%;
  height: 135%;
  transform-origin: 50% 0;
  background: radial-gradient(50% 100% at 50% 0%, rgba(255, 168, 92, 0.2), rgba(255, 128, 48, 0.06) 45%, transparent 78%);
}

.orbit__beams i:nth-child(1) { left: 14%; width: 20vw; }
.orbit__beams i:nth-child(2) { left: 44%; width: 12vw; background: radial-gradient(50% 100% at 50% 0%, rgba(255, 210, 160, 0.16), rgba(255, 170, 110, 0.04) 50%, transparent 80%); }
.orbit__beams i:nth-child(3) { left: 70%; width: 24vw; background: radial-gradient(50% 100% at 50% 0%, rgba(110, 140, 255, 0.12), rgba(80, 110, 255, 0.03) 50%, transparent 80%); }

.orbit__dust {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 50;
  pointer-events: none;
}

/* the still mark, for the layouts without dust */
.orbit__mark {
  display: none;
}

/* ------------------------------------------------------------ the work */
.orbit__works {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* centred on the visible screen and placed by orbit.js with perspective()
   translate3d() rotateY(): the perspective origin is then the screen
   centre, the same camera the dust is drawn with */
.orbit__item,
.orbit__sat {
  position: absolute;
  left: 50%;
  /* the centre of the visible screen with a phone's browser bar shown; the
     stage itself runs on under the bar (orbit.js, viewport()) */
  top: var(--orbit-cy, 50%);
  transform-origin: 50% 50%;
  visibility: hidden;
  will-change: transform, opacity;
}

/* a slab of glass: a front, a back and four sides, t thick */
.orbit__item {
  --r: 16px;
  width: var(--cw, 260px);
  height: var(--ch, 460px);
  margin: calc(var(--ch, 460px) / -2) 0 0 calc(var(--cw, 260px) / -2);
  transform-style: preserve-3d;
}

.orbit__card {
  position: absolute;
  inset: 0;
  display: block;
  overflow: hidden;
  border-radius: var(--r);
  padding: 7px;
  background: rgba(255, 255, 255, 0.07);
  color: #fff;
  text-decoration: none;
  transform: translateZ(calc(var(--t, 16px) / 2));
  backface-visibility: hidden;
  box-shadow: 0 46px 80px -34px rgba(4, 2, 2, 0.95);
}

.orbit__card video,
.orbit__card img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: calc(var(--r) - 6px);
}

/* a site that only scrolls: one long picture of the page, moved by CSS. It
   starts as the hero; orbit.js swaps in the long picture as the slab comes
   round, and the page then runs down and back up. */
.orbit__scroll {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: calc(var(--r) - 6px);
  container-type: size;
}

.orbit__card .orbit__scroll img {
  position: absolute;
  top: 0;
  left: 0;
  height: auto;
  border-radius: 0;
  object-fit: fill;
}

.orbit__scroll.is-long img {
  animation: orbitSiteScroll 13s ease-in-out 1.5s infinite alternate;
}

@keyframes orbitSiteScroll {
  to { transform: translateY(calc(-100% + 100cqh)); }
}

@media (prefers-reduced-motion: reduce) {
  .orbit__scroll.is-long img {
    animation: none;
  }
}

/* the face of the glass: its lip, a glare that travels with the turn, the
   column's orange on the side that faces it, and a thin colour-split rim
   (the brand film's chromatic edge) */
.orbit__glass {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  mix-blend-mode: screen;
  background:
    linear-gradient(112deg, transparent calc(var(--sheen, 0.5) * 100% - 20%), rgba(255, 255, 255, 0.17) calc(var(--sheen, 0.5) * 100%), transparent calc(var(--sheen, 0.5) * 100% + 20%)),
    linear-gradient(90deg, rgba(255, 112, 24, calc(var(--litL, 0) * 0.45)), transparent 32%, transparent 68%, rgba(255, 112, 24, calc(var(--litR, 0) * 0.45))),
    linear-gradient(180deg, rgba(255, 255, 255, 0.1), transparent 24%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.2),
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 0 0 7px rgba(255, 255, 255, 0.035);
}

.orbit__glass::after {
  content: "";
  position: absolute;
  inset: 0;
  padding: 1.5px;
  border-radius: inherit;
  opacity: 0.55;
  background: conic-gradient(from 210deg, rgba(255, 103, 0, 0.9), rgba(255, 255, 255, 0.5), rgba(90, 120, 255, 0.8), rgba(255, 255, 255, 0.25), rgba(255, 103, 0, 0.9));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
}

.orbit__dim {
  position: absolute;
  inset: 0;
  background: #0b0909;
  opacity: var(--dim, 0);
  pointer-events: none;
}

.orbit__side,
.orbit__back {
  position: absolute;
  pointer-events: none;
}

.orbit__side {
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0.36), rgba(255, 255, 255, 0.12) 40%, rgba(255, 255, 255, 0.06));
}

.orbit__side--l,
.orbit__side--r {
  top: var(--r);
  width: var(--t, 16px);
  height: calc(100% - 2 * var(--r));
  backface-visibility: hidden;
}

.orbit__side--l {
  left: calc(var(--t, 16px) / -2);
  transform: rotateY(-90deg);
  background-color: rgba(255, 112, 24, calc(var(--litL, 0) * 0.75));
}

.orbit__side--r {
  left: calc(100% - var(--t, 16px) / 2);
  transform: rotateY(90deg);
  background-color: rgba(255, 112, 24, calc(var(--litR, 0) * 0.75));
}

.orbit__side--t,
.orbit__side--b {
  left: var(--r);
  width: calc(100% - 2 * var(--r));
  height: var(--t, 16px);
}

.orbit__side--t {
  top: calc(var(--t, 16px) / -2);
  transform: rotateX(90deg);
}

.orbit__side--b {
  top: calc(100% - var(--t, 16px) / 2);
  transform: rotateX(-90deg);
  background: rgba(16, 12, 12, 0.92);
}

.orbit__back {
  inset: 0;
  border-radius: var(--r);
  background: linear-gradient(160deg, #1c1616, #0e0b0b);
  transform: rotateY(180deg) translateZ(calc(var(--t, 16px) / 2));
  backface-visibility: hidden;
}

.orbit__cap {
  position: absolute;
  left: 7px;
  right: 7px;
  bottom: 7px;
  display: grid;
  gap: 6px;
  padding: 70px 16px 16px;
  border-radius: 0 0 calc(var(--r) - 6px) calc(var(--r) - 6px);
  background: linear-gradient(to top, rgba(11, 9, 9, 0.88), rgba(11, 9, 9, 0));
  opacity: var(--cap, 1);
}

.orbit__card {
  container-type: inline-size;
}

.orbit__name {
  font: 700 clamp(1.2rem, 1.7vw, 1.65rem) / 1.02 "Syne", sans-serif;
  /* sized to its own card, so a long name (Chrysanthopoulos) fits the narrow
     slabs of the still row as well as the wide ones of the orbit */
  font-size: clamp(1rem, 9cqi, 1.65rem);
  letter-spacing: -0.01em;
  text-wrap: balance;
  /* speed shows as the brand film's chromatic split, only while moving */
  text-shadow:
    calc(var(--vel) * -0.05em) 0 0 rgba(255, 103, 0, 0.85),
    calc(var(--vel) * 0.05em) 0 0 rgba(90, 120, 255, 0.8);
}

.orbit__tag {
  font-size: 0.62rem;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.74);
}

.orbit__card:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: 6px;
}

.orbit__sat {
  width: var(--sw, 200px);
  height: var(--sh, 150px);
  margin: calc(var(--sh, 150px) / -2) 0 0 calc(var(--sw, 200px) / -2);
  overflow: hidden;
  border-radius: 12px;
  padding: 4px;
  background: rgba(255, 255, 255, 0.06);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14), inset 0 1px 0 rgba(255, 255, 255, 0.4), 0 30px 50px -24px rgba(4, 2, 2, 0.9);
}

.orbit__sat img,
.orbit__sat video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 8px;
}

.orbit__sat::after {
  content: "";
  position: absolute;
  inset: 0;
  background: #0b0909;
  opacity: var(--dim, 0.3);
}

/* soft lights hanging close to the lens, out of focus */
.orbit__bokeh i {
  position: absolute;
  left: 50%;
  top: var(--orbit-cy, 50%);
  z-index: 150;
  border-radius: 50%;
  pointer-events: none;
  will-change: transform, opacity;
  background: radial-gradient(circle, rgba(255, 150, 70, 0.34), rgba(255, 110, 30, 0.16) 46%, rgba(255, 100, 20, 0) 70%);
}

.orbit__bokeh i:nth-child(3n + 2) {
  background: radial-gradient(circle, rgba(255, 214, 170, 0.26), rgba(255, 170, 110, 0.1) 46%, rgba(255, 170, 110, 0) 70%);
}

.orbit__bokeh i:nth-child(4) {
  background: radial-gradient(circle, rgba(120, 150, 255, 0.28), rgba(90, 120, 255, 0.1) 46%, rgba(90, 120, 255, 0) 70%);
}

/* the lens: a vignette, film grain, and the flash of the burst */
.orbit__lens {
  position: absolute;
  inset: 0;
  z-index: 180;
  pointer-events: none;
  background: radial-gradient(125% 95% at 50% 46%, transparent 56%, rgba(0, 0, 0, 0.55) 100%);
}

.orbit__lens::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0.07;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.9 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
}

.orbit__flash {
  position: absolute;
  inset: 0;
  opacity: 0;
  mix-blend-mode: screen;
  background: radial-gradient(60% 60% at 70% 48%, rgba(255, 236, 210, 0.9), rgba(255, 140, 50, 0.35) 40%, transparent 75%);
}

/* ------------------------------------------------------------ the copy */
.orbit__copy {
  position: absolute;
  inset: 0;
  z-index: 200;
  pointer-events: none;
}

.orbit__shell {
  position: relative;
  height: 100%;
}

.orbit__intro,
.orbit__label {
  position: absolute;
  left: var(--gut);
  pointer-events: auto;
}

.orbit__intro {
  top: calc(var(--nav-h) + clamp(28px, 7vh, 96px));
  width: min(640px, 52%);
}

.orbit__intro h1 {
  margin-block: 18px clamp(24px, 3.4vw, 44px);
}

.orbit__intro .lead {
  max-width: 44ch;
  color: var(--on-dark-mute);
}

.orbit__intro .eyebrow,
.orbit__label .eyebrow {
  color: var(--on-dark-mute);
}

.orbit__intro .eyebrow .rule {
  background: var(--line-dark);
}

/* the title arrives the way a film's opens: line by line from behind a
   mask, then the rest rises in. CSS, so it runs with the first paint and
   never flickers in after the script. */
@keyframes orbitLine {
  from { clip-path: inset(0 -6% 100% -6%); transform: translateY(0.4em); }
  to { clip-path: inset(-12% -6% -12% -6%); transform: none; }
}

@keyframes orbitRise {
  from { opacity: 0; transform: translateY(16px); }
  to { opacity: 1; transform: none; }
}

.js .orbit__intro h1 > span {
  display: block;
  animation: orbitLine 1.2s var(--ease) both;
  animation-delay: calc(0.3s + var(--i, 0) * 0.14s);
}

.js .orbit__intro .crumbs { animation: orbitRise 0.9s var(--ease) 0.1s both; }
.js .orbit__intro .eyebrow { animation: orbitRise 0.9s var(--ease) 0.62s both; }
.js .orbit__intro .lead { animation: orbitRise 0.9s var(--ease) 0.78s both; }

@media (prefers-reduced-motion: reduce) {
  .js .orbit__intro h1 > span,
  .js .orbit__intro .crumbs,
  .js .orbit__intro .eyebrow,
  .js .orbit__intro .lead {
    animation: none;
  }
}

.orbit__label {
  top: calc(var(--nav-h) + clamp(16px, 4vh, 48px));
  visibility: hidden;
  opacity: 0;
}

.orbit__label .h2 {
  margin: 0;
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.6);
}

/* under the heading: this is a selection, not the whole of the work */
.orbit__sub {
  margin-top: 10px;
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--on-dark-mute);
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.7);
}

/* ------------------------------------------------------------- phones */
@media (max-width: 760px) {
  .orbit__intro {
    right: var(--gut);
    width: auto;
    top: calc(var(--nav-h) + 8px);
  }

  .orbit__intro .lead {
    font-size: 1rem;
  }

  .orbit__item {
    --r: 14px;
  }

  .orbit__cap {
    padding: 52px 13px 13px;
  }

  .orbit__label {
    right: var(--gut);
  }

}

/* ════════════════════════════════════════════════════════════════════
   STILL LAYOUT · reduced motion, no WebGL, no script, a phone on its side
   Nothing travels and, under reduced motion, no clip is fetched: the
   title, the mark beside it, and the same slabs in a row that scrolls
   sideways. Each slab still opens the pop-up (naou.js, initPeek).
   ════════════════════════════════════════════════════════════════════ */
.orbit--still .orbit__stage,
html:not(.js) .orbit__stage {
  position: relative;
  display: flex;
  flex-direction: column;
  height: auto;
  padding: calc(var(--nav-h) + clamp(40px, 6vw, 96px)) 0 clamp(52px, 7vw, 108px);
}

.orbit--still .orbit__world,
html:not(.js) .orbit__world {
  display: contents;
}

.orbit--still .orbit__dust,
.orbit--still .orbit__sats,
.orbit--still .orbit__beams,
.orbit--still .orbit__bokeh,
.orbit--still .orbit__lens,
.orbit--still .orbit__side,
.orbit--still .orbit__back,
html:not(.js) .orbit__dust,
html:not(.js) .orbit__sats,
html:not(.js) .orbit__beams,
html:not(.js) .orbit__bokeh,
html:not(.js) .orbit__lens,
html:not(.js) .orbit__side,
html:not(.js) .orbit__back {
  display: none;
}

.orbit--still .orbit__copy,
html:not(.js) .orbit__copy {
  position: relative;
  inset: auto;
  order: 1;
  z-index: 2;
}

.orbit--still .orbit__intro,
.orbit--still .orbit__label,
html:not(.js) .orbit__intro,
html:not(.js) .orbit__label {
  position: relative;
  left: auto;
  right: auto;
  top: auto;
  visibility: visible;
  opacity: 1;
}

.orbit--still .orbit__label,
html:not(.js) .orbit__label {
  margin-top: clamp(48px, 7vw, 96px);
}

.orbit--still .orbit__mark,
html:not(.js) .orbit__mark {
  display: block;
  position: absolute;
  z-index: 1;
  right: max(var(--gut), 8vw);
  top: calc(var(--nav-h) + clamp(40px, 6vw, 96px));
  width: min(22vw, 260px, 40vh);
  height: auto;
}

.orbit--still .orbit__works,
html:not(.js) .orbit__works {
  order: 2;
  position: relative;
  z-index: 2;
  display: flex;
  gap: 16px;
  overflow-x: auto;
  padding: 28px var(--gut) 8px;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.orbit--still .orbit__item,
html:not(.js) .orbit__item {
  position: relative;
  left: auto;
  top: auto;
  flex: none;
  /* 9:16, and never taller than most of a short screen (a phone on its side) */
  width: calc(min(391px, 64vh) * 0.5625);
  height: min(391px, 64vh);
  margin: 0;
  visibility: visible;
  transform: none;
  transform-style: flat;
  scroll-snap-align: start;
}

/* square slabs (a page of branding, data-orbit-ar="1") */
.orbit--still[data-orbit-ar="1"] .orbit__item,
html:not(.js) .orbit[data-orbit-ar="1"] .orbit__item {
  width: min(300px, 50vh);
  height: min(300px, 50vh);
}

.orbit--still .orbit__card,
html:not(.js) .orbit__card {
  transform: none;
}

@media (max-width: 760px) {
  .orbit--still .orbit__mark,
  html:not(.js) .orbit__mark {
    display: none;
  }
}
