/* =============================================================================
   NMC — Scientific Visual Language & SI Motion System
   -----------------------------------------------------------------------------
   Reusable scientific motifs and the SI-unit motion system that gives the
   platform its visual signature.

   THE RULE THIS FILE OBEYS
   Motion here is ambient, not attention-seeking. Cycles run 17–30s with small
   translation ranges, so at any given glance nothing appears to be moving — the
   scene has simply changed slightly since you last looked. That is what makes it
   read as a scientific instrument rather than a screensaver.

   Every ambient animation multiplies its duration-driving transform by
   `--motion-scale`, which `tokens.css` sets to 0 under prefers-reduced-motion.
   One switch stops everything; no animation is defined without it.

   Components
     .si-orbit          SIOrbit        — the hero SI visualisation
     .si-node           SIUnitNode     — one SI base unit on its orbit
     .sci-grid          ScientificGrid — measurement grid ground
     .sci-ticks         MeasurementTicks — ruler / calibration scale
     .sci-wave          ScienceWave    — faint instrument waveform
     .precision-ring    PrecisionRing  — progress / timer dial
     .metrology-badge   MetrologyBadge — official mark
     .sci-traceability  traceability chain
   ========================================================================== */

/* =============================================================================
   1. ScientificGrid — a measurement ground plane
   ========================================================================== */

.sci-grid {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(47, 128, 201, .16) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(47, 128, 201, .16) 1px, transparent 1px);
  background-size: 64px 64px;
  /* Fades the grid out before it reaches an edge, so it reads as depth rather
     than as a texture someone tiled across the box. */
  -webkit-mask-image: radial-gradient(ellipse 80% 70% at 50% 45%, #000 30%, transparent 78%);
          mask-image: radial-gradient(ellipse 80% 70% at 50% 45%, #000 30%, transparent 78%);
  opacity: .5;
}

.sci-grid--fine { background-size: 24px 24px; opacity: .3; }

/* Drifts exactly one cell, so the loop point is invisible. */
.sci-grid--drift {
  animation: sci-grid-drift var(--science-drift) linear infinite;
}

@keyframes sci-grid-drift {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(calc(64px * var(--motion-scale)), calc(64px * var(--motion-scale)), 0); }
}

/* =============================================================================
   2. MeasurementTicks — ruler / calibration scale
   ========================================================================== */

.sci-ticks {
  --tick-color: rgba(47, 128, 201, .45);
  --tick-gap: 12px;
  height: 14px;
  background-image: repeating-linear-gradient(
    to right,
    var(--tick-color) 0 1px,
    transparent 1px var(--tick-gap)
  );
  /* Every fifth tick runs full height, as on a real rule. */
  background-position: bottom;
  background-repeat: repeat-x;
  background-size: 100% 7px;
  position: relative;
}

.sci-ticks::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(
    to right,
    var(--tick-color) 0 1px,
    transparent 1px calc(var(--tick-gap) * 5)
  );
  background-repeat: repeat-x;
  background-position: bottom;
  background-size: 100% 14px;
}

.sci-ticks--on-dark { --tick-color: rgba(127, 214, 224, .38); }

/* A single calibration rule used to underline section headings. */
.sci-rule {
  height: 1px;
  background: linear-gradient(90deg, var(--nmc-gold) 0, var(--nmc-gold) 48px, var(--border) 48px, var(--border) 100%);
  border: 0;
  margin: 0;
}

/* =============================================================================
   3. ScienceWave — faint instrument trace
   ========================================================================== */

.sci-wave {
  position: absolute;
  left: 0;
  right: 0;
  height: 120px;
  pointer-events: none;
  opacity: .28;
  overflow: hidden;
}

.sci-wave svg { width: 200%; height: 100%; display: block; }

.sci-wave--animate svg {
  animation: sci-wave-scroll 28s linear infinite;
}

@keyframes sci-wave-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(calc(-50% * var(--motion-scale))); }
}

/* =============================================================================
   4. SIOrbit — the hero SI visualisation
   -----------------------------------------------------------------------------
   Structure:
       .si-orbit                square, responsive stage
         .si-orbit__rings       concentric measurement circles
         .si-orbit__core        the central "SI"
         .si-orbit__unit        one per SI base unit, absolutely centred
           .si-node             the visible chip, counter-rotated

   Each unit sits on its own ring at its own angle and revolves on its own
   duration. Because the wrapper rotates and the chip counter-rotates at the same
   rate, the chip travels the orbit while its text stays upright — no unreadable
   tumbling labels.
   ========================================================================== */

.si-orbit {
  position: relative;
  width: 100%;
  max-width: 520px;
  aspect-ratio: 1;
  margin-inline: auto;
  isolation: isolate;
  /* Orbit radii are expressed in cqw so the whole assembly scales with the
     stage rather than against the viewport. */
  container-type: inline-size;
  /* The stage is decorative; the unit list is exposed to assistive tech through
     a visually-hidden list rendered alongside it. */
  pointer-events: none;
}

/* Concentric rings — the measurement circles the units run on. */
.si-orbit__rings {
  position: absolute;
  inset: 0;
  border-radius: 50%;
}

.si-orbit__ring {
  position: absolute;
  top: 50%;
  left: 50%;
  border: 1px solid rgba(127, 214, 224, .18);
  border-radius: 50%;
  transform: translate(-50%, -50%);
}

.si-orbit__ring--1 { width: 44%; height: 44%; }
.si-orbit__ring--2 { width: 67%; height: 67%; border-style: dashed; border-color: rgba(127, 214, 224, .13); }
.si-orbit__ring--3 { width: 90%; height: 90%; border-color: rgba(200, 162, 74, .13); }

/* The two outer rings counter-rotate very slowly. The dashes make the motion
   perceptible; without them a rotating circle is indistinguishable from a still
   one, and the effort would be spent for nothing. */
.si-orbit__ring--2 { animation: si-spin var(--orbit-ring-slow) linear infinite; }
.si-orbit__ring--3 { animation: si-spin var(--orbit-ring-fast) linear infinite reverse; }

@keyframes si-spin {
  from { transform: translate(-50%, -50%) rotate(0deg); }
  to   { transform: translate(-50%, -50%) rotate(calc(360deg * var(--motion-scale))); }
}

/* --- Core ---------------------------------------------------------------- */

.si-orbit__core {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 30%;
  aspect-ratio: 1;
  border-radius: 50%;
  display: grid;
  place-content: center;
  text-align: center;
  background:
    radial-gradient(circle at 50% 42%, rgba(47, 128, 201, .38) 0%, rgba(8, 44, 76, .05) 62%, transparent 72%);
}

.si-orbit__core::before {
  content: "";
  position: absolute;
  inset: 14%;
  border-radius: 50%;
  border: 1px solid rgba(127, 214, 224, .30);
  animation: si-core-pulse var(--science-pulse) var(--ease-science) infinite;
}

/* Extremely subtle: a 4% scale change over 7s. Perceptible only peripherally. */
@keyframes si-core-pulse {
  0%, 100% { transform: scale(1);   opacity: .55; }
  50%      { transform: scale(calc(1 + .04 * var(--motion-scale))); opacity: .9; }
}

.si-orbit__si {
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 5.5vw, 3rem);
  font-weight: var(--weight-display);
  letter-spacing: var(--tracking-tight);
  color: #fff;
  line-height: 1;
  position: relative;
  z-index: 1;
}

.si-orbit__tagline {
  margin-top: var(--space-2);
  font-size: clamp(.6rem, 1.4vw, .72rem);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--science-cyan-soft);
  line-height: 1.4;
  position: relative;
  z-index: 1;
}

/* --- Unit nodes ----------------------------------------------------------- */

/* The wrapper is a full-size layer pinned at the centre; `--radius` pushes the
   chip out along the wrapper's current angle, and rotation of the wrapper walks
   the chip around the ring. */
.si-orbit__unit {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  transform: rotate(var(--angle, 0deg));
  animation: si-orbit-travel var(--duration, 24s) linear infinite;
}

.si-orbit__unit--reverse { animation-direction: reverse; }

@keyframes si-orbit-travel {
  from { transform: rotate(var(--angle, 0deg)); }
  to   { transform: rotate(calc(var(--angle, 0deg) + 360deg * var(--motion-scale))); }
}

.si-node {
  position: absolute;
  /* Out along the orbit, then counter-rotated so the label stays level. */
  transform:
    translate(-50%, -50%)
    translateX(var(--radius, 180px))
    rotate(calc(-1 * var(--angle, 0deg)));
  animation: si-node-level var(--duration, 24s) linear infinite;
  display: grid;
  place-items: center;
  width: var(--node-size, 46px);
  height: var(--node-size, 46px);
  border-radius: 50%;
  background: rgba(9, 39, 66, .82);
  border: 1px solid var(--node-tint, rgba(127, 214, 224, .5));
  box-shadow:
    0 0 0 6px rgba(8, 44, 76, .28),
    0 0 22px -4px var(--node-glow, rgba(39, 183, 199, .55));
  backdrop-filter: blur(2px);
}

.si-orbit__unit--reverse .si-node { animation-direction: reverse; }

@keyframes si-node-level {
  from {
    transform: translate(-50%, -50%) translateX(var(--radius, 180px)) rotate(calc(-1 * var(--angle, 0deg)));
  }
  to {
    transform: translate(-50%, -50%) translateX(var(--radius, 180px))
               rotate(calc(-1 * var(--angle, 0deg) - 360deg * var(--motion-scale)));
  }
}

.si-node__symbol {
  font-family: var(--font-display);
  font-size: calc(var(--node-size, 46px) * .4);
  font-weight: var(--weight-bold);
  color: #fff;
  line-height: 1;
}

/* .si-node__name was removed: the descriptive quantity names are 100-170px wide
   against 52px chips, so at any moment several overlapped a neighbouring node.
   The orbit now carries symbols only; the full names are in the sr-only list. */

/* Per-unit tints. Distinct enough to identify, muted enough to stay a set. */
.si-node[data-unit="m"]   { --node-tint: rgba(127, 214, 224, .55); --node-glow: rgba(39, 183, 199, .5); }
.si-node[data-unit="kg"]  { --node-tint: rgba(47, 128, 201, .6);   --node-glow: rgba(47, 128, 201, .5); }
.si-node[data-unit="s"]   { --node-tint: rgba(225, 198, 117, .55); --node-glow: rgba(200, 162, 74, .45); }
.si-node[data-unit="A"]   { --node-tint: rgba(120, 200, 160, .5);  --node-glow: rgba(22, 131, 74, .42); }
.si-node[data-unit="K"]   { --node-tint: rgba(214, 140, 140, .5);  --node-glow: rgba(183, 53, 53, .35); }
.si-node[data-unit="mol"] { --node-tint: rgba(160, 170, 220, .5);  --node-glow: rgba(90, 110, 200, .4); }
.si-node[data-unit="cd"]  { --node-tint: rgba(225, 198, 117, .5);  --node-glow: rgba(225, 198, 117, .45); }

/* --- Drifting particles --------------------------------------------------- */

.si-orbit__particles { position: absolute; inset: 0; border-radius: 50%; overflow: hidden; }

.si-particle {
  position: absolute;
  width: 2px;
  height: 2px;
  border-radius: 50%;
  background: var(--science-cyan-soft);
  opacity: .5;
  animation: si-particle-drift var(--p-duration, 22s) var(--ease-science) infinite;
  animation-delay: var(--p-delay, 0s);
}

@keyframes si-particle-drift {
  0%   { transform: translate3d(0, 0, 0); opacity: 0; }
  15%  { opacity: .55; }
  85%  { opacity: .35; }
  100% {
    transform: translate3d(calc(var(--p-x, 40px) * var(--motion-scale)),
                           calc(var(--p-y, -60px) * var(--motion-scale)), 0);
    opacity: 0;
  }
}

/* Smaller stage on narrow screens: shrink nodes so labels never overlap. */
@media (max-width: 560px) {
  .si-orbit { max-width: 340px; }
  .si-node { --node-size: 32px; }
}

/* =============================================================================
   5. PrecisionRing — progress / timer dial
   ========================================================================== */

.precision-ring { display: inline-grid; place-items: center; position: relative; }
.precision-ring svg { transform: rotate(-90deg); display: block; }
.precision-ring__track { fill: none; stroke: var(--border); stroke-width: 6; }
.precision-ring__value {
  fill: none;
  stroke: var(--nmc-blue);
  stroke-width: 6;
  stroke-linecap: round;
  /* Set --dash and --offset from JS; the transition animates the sweep. */
  stroke-dasharray: var(--dash, 264);
  stroke-dashoffset: var(--offset, 264);
  transition: stroke-dashoffset 600ms var(--ease-out);
}
.precision-ring--success .precision-ring__value { stroke: var(--success); }
.precision-ring--warning .precision-ring__value { stroke: var(--warning); }
.precision-ring--danger  .precision-ring__value { stroke: var(--danger); }
.precision-ring__label {
  position: absolute;
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}

/* =============================================================================
   6. MetrologyBadge — official mark
   ========================================================================== */

.metrology-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid rgba(200, 162, 74, .45);
  border-radius: var(--radius-pill);
  background: rgba(200, 162, 74, .1);
  color: var(--nmc-gold-light);
  font-size: var(--text-caption);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  line-height: 1;
}

.metrology-badge--light {
  border-color: rgba(150, 118, 47, .35);
  background: var(--nmc-gold-wash);
  color: var(--nmc-gold-deep);
}

.metrology-badge svg { width: 14px; height: 14px; flex: none; }

/* =============================================================================
   7. Traceability chain — the SI-to-certificate lineage motif
   ========================================================================== */

.sci-traceability {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.sci-traceability__node {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-small);
  color: var(--text-secondary);
}

.sci-traceability__dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--science-cyan);
  box-shadow: 0 0 0 3px rgba(39, 183, 199, .16);
  flex: none;
}

.sci-traceability__link {
  flex: 1 1 24px;
  min-width: 24px;
  height: 1px;
  background: repeating-linear-gradient(90deg, var(--border-strong) 0 4px, transparent 4px 8px);
}

/* =============================================================================
   8. Dimensional line — used to annotate figures
   ========================================================================== */

.sci-dimension {
  position: relative;
  height: 1px;
  background: var(--border-strong);
}
.sci-dimension::before,
.sci-dimension::after {
  content: "";
  position: absolute;
  top: -4px;
  width: 1px;
  height: 9px;
  background: var(--border-strong);
}
.sci-dimension::before { left: 0; }
.sci-dimension::after  { right: 0; }

/* =============================================================================
   9. Belt-and-braces reduced motion
   -----------------------------------------------------------------------------
   --motion-scale already flattens every keyframe above to a no-op. This block
   additionally stops the animations outright, so no compositor layer is kept
   alive spending battery on a transform that no longer changes.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .sci-grid--drift,
  .sci-wave--animate svg,
  .si-orbit__ring--2,
  .si-orbit__ring--3,
  .si-orbit__core::before,
  .si-orbit__unit,
  .si-node,
  .si-particle {
    animation: none !important;
  }
  /* Particles exist only as motion; without it they are three grey dots. */
  .si-orbit__particles { display: none; }
}
