/*
  orbit.css
  The crossed elliptical orbit system: static SVG paths, the four SVG
  dots that travel along them, and the four HTML text labels that
  travel alongside those dots. Positioning math lives in
  orbit-geometry.js and orbit-animation.js; this file only handles
  appearance and layering, never transform (that stays entirely
  JavaScript-owned so nothing fights the per-frame position updates).
*/

.hero-orbit-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: var(--comrade-z-orbit-path);
  overflow: visible;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--comrade-transition-slow);
}

.hero-orbit-svg.is-visible {
  opacity: 1;
}

.hero-orbit-path {
  fill: none;
  stroke: var(--comrade-primary);
  stroke-width: 1.25;
  opacity: 0.35;
  vector-effect: non-scaling-stroke;
}

.hero-orbit-path--a {
  opacity: 0.4;
}

.hero-orbit-path--b {
  opacity: 0.28;
}

/*
  The moving dot lives INSIDE this same <svg>, as an SVG <circle>, not
  as an HTML element layered on top (see hero-label.html). That is
  deliberate: it guarantees the dot is rasterized by the exact same
  rendering pipeline, in the exact same coordinate space, as the orbit
  path itself, so there is no possible sub-pixel disagreement between
  two different rendering systems drawing what is meant to be the same
  point.

  Its neumorphic depth (see the #comrade-neumo-dot filter in
  hero-orbit.html) is deliberately tiny: a soft glow makes a dot's true
  center ambiguous to the eye even when it is mathematically exact, and
  this is the one place on the page where "is it actually on the line"
  matters more than tactility. The filter only changes how the circle
  is painted, never its transform, so the mathematically-exact position
  orbit-animation.js writes every frame is completely unaffected.
*/
.hero-orbit-dot {
  fill: var(--comrade-primary);
  vector-effect: non-scaling-stroke;
  filter: url(#comrade-neumo-dot);
  opacity: 0;
  transition: opacity var(--comrade-transition-normal);
  /* Positioned every frame via an SVG transform from orbit-animation.js. */
}

.hero-orbit-dot.is-visible {
  opacity: 1;
}

/*
  The floating icon + text chip is plain HTML/CSS (it needs normal text
  layout), positioned to the identical (x, y) coordinate separately,
  alongside its paired SVG dot. See hero-label.html for how the two are
  paired. This wrapper only carries the shared position; the chip
  inside it (see .hero-orbit-label__chip below) carries the per-side
  offset and layout.
*/
.hero-orbit-label {
  position: absolute;
  top: 0;
  left: 0;
  z-index: var(--comrade-z-orbit-label);
  will-change: transform;
  /* Positioned every frame via transform from orbit-animation.js. */
  transform: translate3d(-9999px, -9999px, 0);
  opacity: 0;
  transition: opacity var(--comrade-transition-normal);
}

.hero-orbit-label.is-visible {
  opacity: 1;
}

/*
  The chip is an icon badge and a text pill riding together as one
  group, offset from the dot. orbit-animation.js sets data-side exactly
  once per label, from its starting position, and never changes it
  again: the chip stays on one fixed side of the dot for the whole
  animation instead of re-anchoring as the dot travels around the
  ellipse. The icon is always the element closest to the dot (an
  anchor) and the text always the furthest (for readability against the
  image); which physical edge that means depends on the side, so each
  [data-side] variant below also sets the flex order, not just the
  offset.
*/
.hero-orbit-label__chip {
  position: absolute;
  top: 0;
  left: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.hero-orbit-label__chip[data-side="right"] {
  flex-direction: row;
  transform: translate(14px, -50%);
}

.hero-orbit-label__chip[data-side="left"] {
  flex-direction: row-reverse;
  transform: translate(calc(-100% - 14px), -50%);
}

.hero-orbit-label__chip[data-side="top"] {
  flex-direction: column-reverse;
  transform: translate(-50%, calc(-100% - 12px));
}

.hero-orbit-label__chip[data-side="bottom"] {
  flex-direction: column;
  transform: translate(-50%, 12px);
}

/*
  A restrained glass LOOK without an actual backdrop-filter. This is
  deliberate: backdrop-filter forces the browser to resample and
  recomposite everything behind the element, and this element moves
  every animation frame, so a live blur here is a real, continuous
  compositing cost on top of the position update, not a one-time cost.
  A single slightly-more-opaque flat color plus a soft border and
  shadow reads as "light, translucent surface" without that ongoing
  per-frame cost. Likewise the dot's glow above is a static box-shadow,
  not a looping CSS animation, for the same reason: nothing should be
  continuously repainting on an element that is also continuously
  moving via JavaScript.
*/
.hero-orbit-label__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  flex-shrink: 0;
  border-radius: 50%;
  background-color: rgba(253, 246, 238, 0.92);
  border: 1px solid rgba(255, 255, 255, 0.7);
  box-shadow: 0 4px 12px var(--comrade-shadow-soft);
  color: var(--comrade-primary);
}

.hero-orbit-label__icon svg {
  width: 15px;
  height: 15px;
}

.hero-orbit-label__text {
  white-space: nowrap;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--comrade-text);
  padding: 0.4rem 0.9rem;
  border-radius: var(--comrade-radius-pill);
  background-color: rgba(253, 246, 238, 0.86);
  border: 1px solid rgba(255, 255, 255, 0.6);
  box-shadow: 0 6px 16px var(--comrade-shadow-soft);
}
