/* ==========================================================================
   Orrery scrollytelling hero

   Progressive enhancement: everything below renders as a calm, fully visible,
   static stack by default — that is what no-JS visitors, crawlers and slow
   connections get, and it is real, on-brand content, not a loading shell.
   module.js adds `.is-enhanced` only once GSAP + ScrollTrigger have loaded,
   the viewport is wide enough, and the visitor hasn't asked for reduced
   motion — only then does the pinned, scroll-scrubbed instrument take over.

   Ring radii are defined once and reused by both the ring circles and the
   translateX distance used to place nodes/spokes on them, so the geometry
   only ever has to change in one place.
   ========================================================================== */

.orrery-hero {
  --r1: clamp(50px, 8vmin, 110px);   /* Strategic Meetings Management (innermost) */
  --r2: clamp(90px, 15vmin, 190px);  /* Managed Services */
  --r3: clamp(130px, 22vmin, 270px); /* Strategy / Platform Selection */
  --r4: clamp(170px, 29vmin, 350px); /* Integrations (second spoke) */
  --r5: clamp(210px, 36vmin, 430px); /* Consulting (outermost) */

  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  overflow: hidden;
  position: relative;
}

/* -------------------------------------------------------------- Load ---- */
/* Only ever shown once .is-enhanced is confirmed — see module.js. */

.orrery-load {
  align-items: center;
  background: var(--bg);
  display: none;
  flex-direction: column;
  gap: 1.4rem;
  height: 100vh;
  justify-content: center;
  left: 0;
  position: absolute;
  top: 0;
  transition: opacity 0.6s ease;
  width: 100%;
  z-index: 5;
}

.is-enhanced .orrery-load {
  display: flex;
}

.orrery-load__ring {
  border: 1px solid var(--ring);
  border-radius: 50%;
  height: 90px;
  opacity: 0;
  transform: scale(0.4);
  width: 90px;
}

.orrery-load__mark {
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.32em;
  margin: 0;
  opacity: 0;
  text-transform: uppercase;
}

.orrery-load.is-hidden {
  opacity: 0;
  pointer-events: none;
}

/* --------------------------------------------------- Static default ---- */

.orrery-track {
  position: relative;
}

.orrery-stage {
  align-items: center;
  display: flex;
  flex-direction: column;
  gap: 3rem;
  justify-content: center;
  padding: 4.5rem 0;
  position: relative;
}

/* .orrery-instrument is the shared box both the CSS rings and the 3D canvas
   fill exactly (inset: 0) — sized once here rather than on each of them, so
   the glow, the CSS fallback and the WebGL canvas always line up. */

.orrery-instrument {
  height: min(70vmin, 420px);
  margin: 0 auto;
  position: relative;
  width: min(70vmin, 420px);
}

.orrery-glow {
  /* Ambient glow — the core's cyan power source, not the chrome instrument
     around it, so this reads on --core rather than --ring. */
  background: radial-gradient(circle, color-mix(in srgb, var(--core) 40%, transparent), transparent 68%);
  height: 145%;
  left: 50%;
  pointer-events: none;
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 145%;
  z-index: 0;
}

.orrery-visual,
.orrery-3d-mount {
  inset: 0;
  position: absolute;
  z-index: 1;
}

.orrery-3d-mount:empty {
  display: none;
}

.orrery-3d-mount canvas {
  display: block;
  height: 100%;
  width: 100%;
}

.orrery-hero.has-3d .orrery-visual {
  display: none;
}

.orrery-core {
  /* The core is the instrument's one power source — cyan (--core), not the
     chrome (--ring) the rings/spokes/nodes are built from. */
  align-items: center;
  background: radial-gradient(circle at 40% 35%, color-mix(in srgb, var(--core) 55%, white 20%), color-mix(in srgb, var(--core) 35%, transparent) 60%, transparent 100%);
  border-radius: 50%;
  box-shadow: 0 0 60px 10px color-mix(in srgb, var(--core) 45%, transparent);
  display: flex;
  height: 74px;
  justify-content: center;
  left: 50%;
  opacity: 1;
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%) scale(1);
  width: 74px;
}

.orrery-core img {
  filter: drop-shadow(0 0 10px color-mix(in srgb, var(--core) 65%, transparent));
  height: auto;
  max-height: 68%;
  max-width: 68%;
  object-fit: contain;
  width: auto;
}

.orrery-ring {
  border: 1px solid color-mix(in srgb, var(--ring) 35%, transparent);
  border-radius: 50%;
  left: 50%;
  opacity: 1;
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%) scale(1) rotate(0deg);
}

.orrery-ring--1 { width: calc(var(--r1) * 2); height: calc(var(--r1) * 2); }
.orrery-ring--2 { width: calc(var(--r2) * 2); height: calc(var(--r2) * 2); }
.orrery-ring--3 { width: calc(var(--r3) * 2); height: calc(var(--r3) * 2); }
.orrery-ring--4 { width: calc(var(--r4) * 2); height: calc(var(--r4) * 2); }
.orrery-ring--5 { width: calc(var(--r5) * 2); height: calc(var(--r5) * 2); }

.orrery-ring.is-live {
  animation: orrery-spin 14s linear infinite;
}

@keyframes orrery-spin {
  to { transform: translate(-50%, -50%) rotate(360deg); }
}

.orrery-node {
  left: 50%;
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%) rotate(var(--angle)) translateX(var(--r3));
}

.orrery-node__dot {
  background: var(--tech);
  border-radius: 50%;
  display: block;
  height: 7px;
  opacity: 1;
  transform: rotate(calc(-1 * var(--angle)));
  transition: opacity 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;
  width: 7px;
}

/* Chrome by default (part of the structural skeleton) — a small cyan glow
   only on interaction, a live-instrument detail rather than a full recolor. */

.orrery-node:hover .orrery-node__dot,
.orrery-node:focus-visible .orrery-node__dot {
  box-shadow: 0 0 8px 2px color-mix(in srgb, var(--core) 55%, transparent);
}

.orrery-node__tag {
  color: var(--ring);
  display: block;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  margin-top: 4px;
  opacity: 1;
  transform: rotate(calc(-1 * var(--angle)));
  white-space: nowrap;
}

.orrery-spoke {
  background: var(--ring);
  height: 2px;
  left: 50%;
  opacity: 0.6;
  position: absolute;
  top: 50%;
  transform-origin: 0 50%;
  transform: translateY(-50%) rotate(var(--angle));
  width: var(--len);
}

.orrery-spoke--talent {
  background: var(--talent);
}

.orrery-panels {
  display: contents;
}

.orrery-panel {
  margin: 0 auto;
  max-width: 480px;
  opacity: 1;
  padding: 0 1.4rem;
  text-align: center;
  transform: none;
}

/* Mobile-only glass card — same recipe as the desktop instrument's panel,
   toned down, so the text has its own surface against the dark scene
   instead of floating directly on it. Not scoped to .is-enhanced (that
   never applies below 900px) — a plain width query instead. */

@media (max-width: 899px) {
  .orrery-panel {
    background: linear-gradient(155deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.02));
    backdrop-filter: blur(16px) saturate(160%);
    -webkit-backdrop-filter: blur(16px) saturate(160%);
    border: 1px solid rgba(255, 255, 255, 0.14);
    box-shadow: 0 20px 40px -22px rgba(0, 0, 0, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.1);
    padding: 1.8rem 1.6rem;
  }

  @supports not (backdrop-filter: blur(1px)) {
    .orrery-panel {
      background: color-mix(in srgb, var(--bg) 85%, transparent);
    }
  }
}

/* Mobile-only reveal — module.js adds .is-mobile-revealing only once it's
   confirmed IntersectionObserver is available and reduced-motion isn't
   set; the hero panel (shown immediately, no scroll needed) is excluded.
   Without JS, or on the enhanced desktop instrument, panels are untouched
   by this and stay at the plain opacity:1 above. */

.orrery-hero.is-mobile-revealing .orrery-panel:not([data-beat="hero"]) {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.orrery-hero.is-mobile-revealing .orrery-panel.is-in-view {
  opacity: 1;
  transform: translateY(0);
}

.orrery-eyebrow {
  color: var(--tech);
  display: block;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  margin-bottom: 0.7em;
  text-transform: uppercase;
}

.orrery-headline {
  color: var(--ink);
  font-family: var(--font-heading);
  font-size: clamp(1.9rem, 4vw, 3.2rem);
  line-height: 1.08;
  margin: 0 0 0.4em;
}

.orrery-headline--pillar {
  font-size: clamp(1.5rem, 2.8vw, 2.1rem);
}

.orrery-sub,
.orrery-body {
  color: color-mix(in srgb, var(--ink) 78%, transparent);
  font-size: 1rem;
  line-height: 1.6;
  margin: 0 0 0.6em;
}

.orrery-body p {
  margin: 0;
}

.orrery-cue {
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.2em;
  margin-top: 1.6em;
  text-transform: uppercase;
}

.orrery-industry-caption {
  color: var(--talent);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  margin-top: 1em;
  min-height: 1.2em;
  text-transform: uppercase;
}

/* ============================================================ ENHANCED ==
   Pinned, scroll-scrubbed instrument. Applied only by module.js, only when
   GSAP + ScrollTrigger are ready, the viewport is ≥ 900px, and the visitor
   has not requested reduced motion.
   ========================================================================== */

.is-enhanced.orrery-hero { overflow: visible; }

.is-enhanced .orrery-track {
  height: var(--track-h, 1100vh);
}

.is-enhanced .orrery-stage {
  flex-direction: row;
  gap: 0;
  height: 100vh;
  left: 0;
  overflow: hidden;
  padding: 0;
  position: sticky;
  top: 0;
  width: 100%;
}

.is-enhanced .orrery-instrument {
  height: 100%;
  inset: 0;
  margin: 0;
  position: absolute;
  width: 100%;
}

/* At 1150px+ the panel sits beside the instrument rather than below it (see
   the panel rules further down), so there's no bottom band competing for
   vertical room — nudge the instrument up slightly to use that space. */

@media (min-width: 1150px) {
  .is-enhanced .orrery-instrument {
    transform: translateY(-40px);
  }
}

.is-enhanced .orrery-core {
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.3);
}

.is-enhanced .orrery-ring {
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.85) rotate(0deg);
}

.is-enhanced .orrery-node__dot {
  opacity: 0.35;
}

.is-enhanced .orrery-node.is-winner .orrery-node__dot {
  background: var(--tech);
  opacity: 1;
  transform: rotate(calc(-1 * var(--angle))) scale(1.5);
}

.is-enhanced .orrery-node__tag {
  opacity: 0;
  transition: opacity 0.4s ease;
}

.is-enhanced .orrery-node.show-tag .orrery-node__tag {
  opacity: 1;
}

.is-enhanced .orrery-spoke {
  opacity: 0;
  width: 0;
}

.is-enhanced .orrery-panels {
  display: block;
  height: 100%;
  left: 0;
  pointer-events: none;
  position: absolute;
  top: 0;
  width: 100%;
  z-index: 2;
}

/* Glass card — the panel sits in front of the 3D scene, so it needs its own
   quiet surface to stay readable over whatever is moving behind it. */

.is-enhanced .orrery-panel {
  background: linear-gradient(155deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.025));
  backdrop-filter: blur(22px) saturate(180%);
  -webkit-backdrop-filter: blur(22px) saturate(180%);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 0;
  box-shadow:
    0 24px 48px -20px rgba(0, 0, 0, 0.6),
    inset 0 1px 0 rgba(255, 255, 255, 0.12),
    inset 0 0 0 1px rgba(255, 255, 255, 0.03);
  left: 6%;
  margin: 0;
  max-width: 34ch;
  opacity: 0;
  padding: 2rem 2.2rem;
  position: absolute;
  right: auto;
  text-align: left;
  top: 50%;
  transform: translateY(24px);
}

@supports not (backdrop-filter: blur(1px)) {
  .is-enhanced .orrery-panel {
    background: color-mix(in srgb, var(--bg) 82%, transparent);
  }
}

.is-enhanced .orrery-panel[data-beat="strategy"],
.is-enhanced .orrery-panel[data-beat="implementation"],
.is-enhanced .orrery-panel[data-beat="managed_services"],
.is-enhanced .orrery-panel[data-beat="talent"] {
  left: auto;
  right: 6%;
}

/* Below 1150px (still ≥900px, so the full 3D instrument is running) the
   side card's footprint starts crowding the instrument — same card as
   1150px+ (above), just narrower, so it takes less width from the
   instrument; the same text naturally wraps to more lines and the card
   grows taller as a result. */

@media (min-width: 900px) and (max-width: 1149px) {
  .is-enhanced .orrery-panel {
    left: 6%;
    max-width: 22ch;
    padding: 1.6rem 1.8rem;
  }

  .is-enhanced .orrery-panel[data-beat="strategy"],
  .is-enhanced .orrery-panel[data-beat="implementation"],
  .is-enhanced .orrery-panel[data-beat="managed_services"],
  .is-enhanced .orrery-panel[data-beat="talent"] {
    left: auto;
    right: 6%;
  }

  .is-enhanced .orrery-headline {
    font-size: clamp(1.4rem, 2.6vw, 2rem);
  }

  .is-enhanced .orrery-sub,
  .is-enhanced .orrery-body {
    font-size: 0.88rem;
  }

  /* The ecosystem beat carries an extra line (the cycling industry caption)
     on top of the usual headline+body — at the same 22ch as every other
     panel that extra content stretches it too tall, so it gets more room. */
  .is-enhanced .orrery-panel[data-beat="ecosystem"] {
    max-width: 30ch;
  }

  .is-enhanced .orrery-industry-caption {
    font-size: 0.66rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .orrery-ring.is-live {
    animation: none;
  }
}
