/* Xeroverse landing — experimental scroll-orbit hero (docs/HERO-SCROLL-ORBIT.md).
   Served ONLY when PLATFORM_HERO_VARIANT=scroll-orbit. Every rule is gated on
   html.xo-on, which hero-orbit.js adds only when: JS runs, 3D transforms are
   supported, the viewer does not prefer reduced motion and the device is not
   save-data/low-memory. Without that class the approved hero is untouched —
   that IS the fallback composition (logo + static orbit + readable cards).
   No external assets: everything here is CSS + inline SVG from hero-orbit.js. */

/* =================== scroll shell =================== */
.xo-on .xo-scroll { position: relative; }
/* xo-d: >1060px, pins the whole hero (copy stays beside the orbit).
   xo-m: ≤1060px, where the approved hero stacks — the headline scrolls
   normally and only the stage is pinned below it (never clipped). */
.xo-on .xo-scroll.xo-d { height: 260vh; height: 260svh; }
.xo-on .xo-scroll.xo-m { height: 200vh; height: 200svh; }
/* clip (NOT hidden — hidden would break position:sticky) kills sideways bleed */
.xo-on .xo-scroll { overflow-x: clip; }
.xo-on .xo-d > .xl-hero {
  position: sticky; top: 0;
  height: 100vh; height: 100svh;
  box-sizing: border-box;
  display: grid; align-content: center;
  overflow: clip;
}
.xo-on .xo-d .xl-hero-grid { min-height: 0; }
.xo-on .xo-m .xo-sticky {
  position: sticky; top: 0;
  height: 100vh; height: 100svh;
  display: flex; align-items: center; justify-content: center;
  overflow: clip;
}
.xo-on .xo-m .xl-stage { margin: 0 auto; }
/* keep headline/CTA above any orbital drift; copy is never covered */
.xo-on .xl-hero-copy { position: relative; z-index: 40; }

/* =================== stage becomes a 3D theatre =================== */
.xo-on .xl-stage { perspective: 1150px; perspective-origin: 50% 42%; }
/* legacy decoration off in orbit mode (the orbit is scroll-driven now) */
.xo-on .xl-orbit { animation: none; }
.xo-on .xl-spoke { display: none; }
.xo-on .xl-stage-rings i:nth-child(1) { opacity: calc(0.35 + var(--xo-est, 0) * 0.65); }
.xo-on .xl-stage-rings i:nth-child(2) {
  opacity: calc(0.3 + var(--xo-est, 0) * 0.7);
  transform: translate(-50%, -50%) rotateX(calc(var(--xo-est, 0) * 58deg));
}
.xo-on .xl-stage-rings i:nth-child(3) { opacity: 0.5; }

/* project-coordinate grid — activates during Phase 1 */
.xo-on .xo-grid {
  position: absolute; left: 50%; top: 58%; width: 150%; aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%) rotateX(72deg);
  background-image:
    repeating-linear-gradient(0deg, rgba(233, 200, 126, 0.12) 0 1px, transparent 1px 40px),
    repeating-linear-gradient(90deg, rgba(233, 200, 126, 0.12) 0 1px, transparent 1px 40px);
  -webkit-mask-image: radial-gradient(circle at 50% 50%, #000 22%, transparent 66%);
  mask-image: radial-gradient(circle at 50% 50%, #000 22%, transparent 66%);
  opacity: calc(var(--xo-est, 0) * 0.55);
  pointer-events: none;
}
/* projected orbit path — an ellipse matching the card orbit */
.xo-on .xo-path {
  position: absolute; left: 50%; top: calc(50% + 8.5cqw);
  width: 76cqw; height: 40cqw; /* matches the orbit's actual projected ellipse */
  transform: translate(-50%, -50%);
  border: 1px dashed rgba(233, 200, 126, 0.35);
  border-radius: 50%;
  opacity: calc(var(--xo-est, 0) * 0.55);
  pointer-events: none;
}

/* core reactions: stable logo, restrained glow that answers the front service.
   The core lives INSIDE .xo-world at z=0 — real 3D depth sorting layers it. */
.xo-on .xl-stage-core {
  animation: none;
  transform: translate(-50%, -50%) scale(calc(1 + var(--xo-core, 0) * 0.045));
  box-shadow:
    0 0 calc(46px + var(--xo-core, 0) * 44px) rgba(233, 200, 126, calc(0.08 + var(--xo-core, 0) * 0.16)),
    inset 0 0 34px rgba(13, 17, 23, 0.6);
  transition: none;
}

/* =================== orbiting service cards =================== */
.xo-on .xo-world {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  pointer-events: none;
}
.xo-on .xo-card {
  position: absolute; left: 50%; top: 50%;
  width: clamp(178px, 46cqw, 258px);
  will-change: transform, opacity;
  pointer-events: auto;
}
.xo-on .xo-card-in {
  border-radius: 18px;
  background: linear-gradient(165deg, rgba(20, 25, 34, 0.94), rgba(13, 17, 23, 0.9));
  border: 1px solid rgba(233, 200, 126, calc(0.14 + var(--xo-d, 0.5) * 0.36));
  box-shadow: 0 calc(8px + var(--xo-d, 0.5) * 16px) calc(22px + var(--xo-d, 0.5) * 26px) rgba(6, 8, 12, calc(0.35 + var(--xo-d, 0.5) * 0.3));
  padding: 8px 8px 10px;
}
/* the anchor stays a normal link: readable label row under the scene */
.xo-on .xo-card .xl-node { position: static; transform: none; display: block; text-decoration: none; }
.xo-on .xo-card .xl-node-in {
  animation: none; transform: none;
  flex-direction: row; justify-content: center; gap: 9px;
  background: none; border: none; box-shadow: none;
  padding: 6px 4px 2px; min-width: 0;
}
.xo-on .xo-card .xl-node-in b { font-size: 15px; }
.xo-on .xo-card .xl-node-in span { font-size: 12px; }
.xo-on .xo-card .xl-node:focus-visible { outline: 2px solid var(--xl-gold); outline-offset: 3px; border-radius: 12px; }

/* =================== phase-5: connection beams + platform line =================== */
.xo-on .xo-links { position: absolute; inset: 0; pointer-events: none; }
.xo-on .xo-links line {
  stroke: rgba(233, 200, 126, 0.5); stroke-width: 1;
  stroke-dasharray: 1; stroke-dashoffset: calc(1 - var(--xo-conn, 0));
  opacity: calc(var(--xo-conn, 0) * 0.7);
}
.xo-on .xo-msg {
  /* anchored BELOW the stage (top, not bottom) and scaled in container units:
     the front card overhangs the stage bottom by ~6cqw (9cqw on phones), so a
     stage-relative offset keeps the message clear at every size — wrapping to
     two lines can only grow downward, never up into the card */
  position: absolute; left: 50%; top: calc(100% + 10cqw);
  transform: translate(-50%, calc((1 - var(--xo-conn, 0)) * 14px));
  width: max-content; max-width: 92%;
  font-family: var(--xl-font-head); font-weight: 500; font-size: 13.5px;
  letter-spacing: 1.6px; text-transform: uppercase; text-align: center;
  color: var(--xl-gold-hi);
  opacity: calc(var(--xo-conn, 0) * 0.95);
  pointer-events: none;
}

/* =================== scenes — shared linework =================== */
.xo-on .xo-scene { display: block; width: 100%; aspect-ratio: 3 / 2; }
.xo-scene .ln { fill: none; stroke: rgba(223, 229, 238, 0.5); stroke-width: 1.3; stroke-linecap: round; stroke-linejoin: round; }
.xo-scene .lng { fill: none; stroke: rgba(233, 200, 126, 0.75); stroke-width: 1.3; stroke-linecap: round; stroke-linejoin: round; }
.xo-scene .fill-dark { fill: rgba(10, 13, 18, 0.85); }
.xo-scene .fill-glass { fill: rgba(223, 229, 238, 0.07); }
.xo-scene .fill-gold { fill: var(--xl-gold, #e9c87e); }
.xo-scene .person { fill: #161b23; stroke: rgba(233, 200, 126, 0.55); stroke-width: 0.9; }

/* Every scene element keys off --xo-ph (0→1 while its service is front).
   Pattern: opacity/transform = clamp(0, (ph - start) / window, 1).
   Ground planes and main structures rest as a faint blueprint ghost (opacity
   floor) so cards never look empty; details are true reveals. */

/* ---- VisionWalk: premium interior + VR buyer ---- */
.xo-sc .st-early { opacity: clamp(0.4, calc(var(--xo-ph, 0) * 4), 1); }
.xo-sc-vw .vw-walls {
  opacity: clamp(0.25, calc((var(--xo-ph, 0) - 0.06) * 4), 1);
  transform: translateY(calc(clamp(0, calc(1 - (var(--xo-ph, 0) - 0.06) * 4), 1) * 8px));
}
.xo-sc-vw .vw-horizon { opacity: clamp(0, calc((var(--xo-ph, 0) - 0.28) * 4), 1); }
.xo-sc-vw .vw-furniture { opacity: clamp(0, calc((var(--xo-ph, 0) - 0.34) * 4), 1); }
.xo-sc-vw .vw-plan { opacity: calc(clamp(0, calc(var(--xo-ph, 0) * 3), 1) * 0.5); }
.xo-sc-vw .vw-ring {
  stroke-dasharray: 1;
  stroke-dashoffset: clamp(0, calc(1 - (var(--xo-ph, 0) - 0.42) * 2.4), 1);
  opacity: clamp(0, calc((var(--xo-ph, 0) - 0.42) * 4), 1);
}
.xo-sc-vw .vw-hs {
  opacity: clamp(0, calc((var(--xo-ph, 0) - 0.58) * 5), 1);
  transform: scale(clamp(0.4, calc((var(--xo-ph, 0) - 0.58) * 5), 1));
  transform-box: fill-box; transform-origin: center;
}
.xo-sc-vw .vw-person {
  opacity: clamp(0, calc((var(--xo-ph, 0) - 0.5) * 3.4), 1);
  transform: translateY(calc(clamp(0, calc(1 - (var(--xo-ph, 0) - 0.5) * 3.4), 1) * 7px));
}

/* ---- Immersive Maps: project pin, routes, amenities, tablet viewer ---- */
.xo-sc-im .im-tower {
  opacity: clamp(0.25, calc((var(--xo-ph, 0) - 0.06) * 4), 1);
  transform: translateY(calc(clamp(0, calc(1 - (var(--xo-ph, 0) - 0.06) * 4), 1) * 8px));
}
.xo-sc-im .im-pin {
  opacity: clamp(0, calc((var(--xo-ph, 0) - 0.22) * 5), 1);
  transform: translateY(calc(clamp(0, calc(1 - (var(--xo-ph, 0) - 0.22) * 5), 1) * -9px));
}
.xo-sc-im .im-roads {
  stroke-dasharray: 1;
  stroke-dashoffset: clamp(0, calc(1 - (var(--xo-ph, 0) - 0.3) * 2.6), 1);
  opacity: clamp(0, calc((var(--xo-ph, 0) - 0.3) * 4), 1);
}
.xo-sc-im .im-am {
  opacity: clamp(0, calc((var(--xo-ph, 0) - 0.52) * 4.5), 1);
  transform: scale(clamp(0.5, calc((var(--xo-ph, 0) - 0.52) * 4.5), 1));
  transform-box: fill-box; transform-origin: center;
}
.xo-sc-im .im-mkt { opacity: calc(clamp(0, calc((var(--xo-ph, 0) - 0.66) * 5), 1) * 0.65); }
.xo-sc-im .im-person { opacity: clamp(0, calc((var(--xo-ph, 0) - 0.4) * 3.2), 1); }
.xo-sc-im .im-beam { opacity: calc(clamp(0, calc((var(--xo-ph, 0) - 0.55) * 4), 1) * 0.8); }

/* ---- SpaceFlow: massing → floor plates → unit → 360, elevated observer ---- */
.xo-sc-sf .sf-city { opacity: calc(clamp(0, calc(var(--xo-ph, 0) * 3.2), 1) * 0.55); }
.xo-sc-sf .sf-plate { transform: translateY(0); }
.xo-sc-sf .sf-p1 { transform: translateY(calc(clamp(0, calc((var(--xo-ph, 0) - 0.2) * 3), 1) * -6px)); }
.xo-sc-sf .sf-p2 { transform: translateY(calc(clamp(0, calc((var(--xo-ph, 0) - 0.2) * 3), 1) * -14px)); }
.xo-sc-sf .sf-p3 { transform: translateY(calc(clamp(0, calc((var(--xo-ph, 0) - 0.2) * 3), 1) * -22px)); }
.xo-sc-sf .sf-p4 { transform: translateY(calc(clamp(0, calc((var(--xo-ph, 0) - 0.2) * 3), 1) * -30px)); }
.xo-sc-sf .sf-sel { opacity: clamp(0, calc((var(--xo-ph, 0) - 0.5) * 5), 1); }
.xo-sc-sf .sf-unit { opacity: clamp(0, calc((var(--xo-ph, 0) - 0.64) * 5), 1); }
.xo-sc-sf .sf-360 {
  opacity: clamp(0, calc((var(--xo-ph, 0) - 0.78) * 6), 1);
  transform: scale(clamp(0.5, calc((var(--xo-ph, 0) - 0.78) * 6), 1));
  transform-box: fill-box; transform-origin: center;
}
.xo-sc-sf .sf-deck { opacity: clamp(0, calc((var(--xo-ph, 0) - 0.34) * 3.4), 1); }
.xo-sc-sf .sf-person { opacity: clamp(0, calc((var(--xo-ph, 0) - 0.44) * 3.4), 1); }

/* =================== tablet =================== */
@media (max-width: 1100px) {
  .xo-on .xo-card { width: clamp(165px, 44cqw, 225px); }
  .xo-on .xo-msg { font-size: 12px; }
}

/* =================== mobile =================== */
@media (max-width: 760px) {
  .xo-on .xo-card { width: clamp(158px, 52cqw, 205px); }
  /* reduce visual complexity + expensive effects */
  .xo-sc-vw .vw-plan, .xo-sc-im .im-mkt, .xo-sc-im .im-beam { display: none; }
  .xo-on .xo-grid { display: none; }
  .xo-on .xo-msg { top: calc(100% + 12cqw); font-size: 11.5px; letter-spacing: 1.2px; }
}

/* =================== reduced motion belt-and-braces ===================
   hero-orbit.js never activates under prefers-reduced-motion, so xo-on is
   absent and the approved static hero renders. If the preference flips while
   the page is open, neutralize the shell so scrolling is immediate. */
@media (prefers-reduced-motion: reduce) {
  .xo-on .xo-scroll.xo-d, .xo-on .xo-scroll.xo-m { height: auto; }
  .xo-on .xo-d > .xl-hero, .xo-on .xo-m .xo-sticky { position: static; height: auto; }
}
