@import url("https://fonts.googleapis.com/css2?family=Rajdhani:wght@400;500;600;700&family=Share+Tech+Mono&display=swap");

:root {
  --bg-0: #03070d;
  --bg-1: #061322;
  --cyan: #4dd9ff;
  --cyan-soft: rgba(77, 217, 255, 0.55);
  --cyan-faint: rgba(77, 217, 255, 0.12);
  --gold: #e7d489;
  --text: #d8f1ff;
  --text-dim: rgba(216, 241, 255, 0.55);
  --panel-bg: rgba(6, 19, 34, 0.72);
  --hud-line: rgba(77, 217, 255, 0.45);
  color: var(--text);
  font-family: "Rajdhani", system-ui, sans-serif;
  font-synthesis: none;
  text-rendering: geometricPrecision;
}

* { box-sizing: border-box; }

html, body { margin: 0; min-height: 100vh; background: var(--bg-0); overflow: hidden; }

button { font: inherit; -webkit-tap-highlight-color: transparent; }

/* === SHELL =============================================================== */

.appShell {
  position: relative;
  width: 100vw;
  height: 100vh;
  padding: 8px 18px 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  background:
    radial-gradient(ellipse at 50% 60%, rgba(20, 60, 90, 0.45) 0%, transparent 55%),
    linear-gradient(180deg, #02060c 0%, #061425 60%, #02070c 100%);
  overflow: hidden;
}

.bgGrid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(77, 217, 255, 0.06) 1px, transparent 1px),
    linear-gradient(90deg, rgba(77, 217, 255, 0.06) 1px, transparent 1px);
  background-size: 38px 38px;
  mask-image: radial-gradient(ellipse at center, #000 30%, transparent 85%);
  pointer-events: none;
}

.bgGlow {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(circle at 20% 20%, rgba(77, 217, 255, 0.10), transparent 42%),
    radial-gradient(circle at 80% 70%, rgba(255, 184, 77, 0.06), transparent 45%),
    radial-gradient(circle at 50% 50%, rgba(77, 217, 255, 0.04), transparent 70%);
  pointer-events: none;
}

/* Global soft bloom overlay — like an After Effects Glow pass at low intensity */

.appShell::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse at center, transparent 40%, rgba(0, 0, 0, 0.35) 100%);
  z-index: 1;
}

.appShell::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    repeating-linear-gradient(
      0deg,
      rgba(77, 217, 255, 0.018) 0px,
      rgba(77, 217, 255, 0.018) 1px,
      transparent 1px,
      transparent 3px
    );
  mix-blend-mode: screen;
  z-index: 1;
}

.appShell > * { position: relative; z-index: 2; }

/* === HUD FRAME =========================================================== */

.hudFrame {
  position: relative;
  background: var(--panel-bg);
  border: 1px solid var(--hud-line);
  border-radius: 2px;
  padding: 10px 14px;
  backdrop-filter: blur(6px);
  box-shadow:
    inset 0 0 0 1px rgba(77, 217, 255, 0.10),
    inset 0 0 18px rgba(77, 217, 255, 0.04),
    0 0 14px rgba(77, 217, 255, 0.10),
    0 0 38px rgba(77, 217, 255, 0.06);
}

.hudCorner {
  position: absolute;
  width: 10px;
  height: 10px;
  border: 2px solid var(--cyan);
  pointer-events: none;
  filter: drop-shadow(0 0 4px rgba(77, 217, 255, 0.7));
}

.hudCorner.tl { top: -1px; left: -1px; border-right: 0; border-bottom: 0; }

.hudCorner.tr { top: -1px; right: -1px; border-left: 0; border-bottom: 0; }

.hudCorner.bl { bottom: -1px; left: -1px; border-right: 0; border-top: 0; }

.hudCorner.br { bottom: -1px; right: -1px; border-left: 0; border-top: 0; }

/* === TOP ROW ============================================================= */

.topRow {
  display: grid;
  /* 3-column layout matching the mainGrid: brand (left col width) | title
     (center, flexible) | mission chip (right col width). Brand and mission
     HUD frames hug their content; the title block sets the row height. */
  grid-template-columns: 280px 1fr 320px;
  gap: 12px;
  align-items: start;
  flex-shrink: 0;
  position: relative;
}

.topRow > .hudFrame:first-child,
.topRow > .hudFrame:last-child {
  /* Brand + mission boxes: intrinsic height, never stretch with the title. */
  align-self: start;
}

/* Soft amber accent band across the header to break up the heavy negative
   space and complement the dominant cyan with a warm color. */

.topRow::before {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 50%;
  height: 1px;
  transform: translateY(-0.5px);
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(77, 217, 255, 0.30) 18%,
    rgba(255, 156, 64, 0.45) 50%,
    rgba(77, 217, 255, 0.30) 82%,
    transparent 100%);
  filter: drop-shadow(0 0 4px rgba(255, 156, 64, 0.4));
  pointer-events: none;
  z-index: 0;
}

.topRow > * { position: relative; z-index: 1; }

.titleBlock {
  text-align: center;
  position: relative;
  padding: 4px 14px 6px;
}

/* Subtle vignette behind the title to anchor it visually */

.titleBlock::after {
  content: '';
  position: absolute;
  inset: 4px 0;
  background: radial-gradient(ellipse 65% 80% at center,
    rgba(77, 217, 255, 0.10) 0%,
    rgba(255, 156, 64, 0.05) 45%,
    transparent 75%);
  pointer-events: none;
  z-index: -1;
}

.titleBlock h1 {
  margin: 0;
  font-size: clamp(20px, 2.1vw, 32px);
  font-weight: 700;
  letter-spacing: 0.30em;
  color: var(--text);
  text-shadow:
    0 0 12px rgba(77, 217, 255, 0.55),
    0 0 30px rgba(77, 217, 255, 0.25);
}

.titleBlock h1 .accentWord {
  color: #ffb273;
  text-shadow:
    0 0 12px rgba(255, 156, 64, 0.65),
    0 0 28px rgba(255, 156, 64, 0.30);
}

.titleBlock p {
  margin: 6px 0 0;
  font-family: "Share Tech Mono", monospace;
  font-size: 12px;
  letter-spacing: 0.24em;
  color: var(--cyan);
  opacity: 0.9;
}

.titleBlock p .pipe { color: rgba(255, 156, 64, 0.85); padding: 0 4px; }

/* === BLADE A · B · C SUBTITLE ============================================ */

/* Three chips on one line below the main title. The chip matching the blade
   currently being inspected glows in amber; the other two stay subdued and
   light up on hover. */

.bladeRow {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 20px;
  /* Extra top margin so the chips sit well clear of the subtitle line. */
  margin: 32px 0 6px;
  font-family: "Share Tech Mono", monospace;
}

.bladeChip {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 11px;
  padding: 10px 23px;
  font-size: 14px;
  letter-spacing: 0.32em;
  color: rgba(160, 200, 220, 0.55);
  background: rgba(77, 217, 255, 0.04);
  border: 1px solid rgba(77, 217, 255, 0.18);
  border-radius: 999px;
  /* Now a real <button> — make it look identical to the old <span> chip
     and behave like an interactive control. */
  font-family: inherit;
  text-transform: inherit;
  cursor: pointer;
  user-select: none;
  outline: none;
  transition: color 0.25s ease, background 0.25s ease, border-color 0.25s ease,
    box-shadow 0.25s ease, transform 0.25s ease;
}

.bladeChip:focus-visible {
  box-shadow:
    0 0 0 2px rgba(77, 217, 255, 0.85),
    0 0 14px rgba(77, 217, 255, 0.45);
}

.bladeChipDisabled,
.bladeChip:disabled {
  opacity: 0.35;
  cursor: not-allowed;
  pointer-events: none;
}

.bladeChip strong {
  font-weight: 700;
  letter-spacing: 0.18em;
  color: inherit;
}

.bladeChipDot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: rgba(160, 200, 220, 0.35);
  box-shadow: 0 0 0 2px rgba(77, 217, 255, 0.08);
  transition: background 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease;
}

.bladeChip:hover {
  color: rgba(220, 240, 255, 0.95);
  background: rgba(77, 217, 255, 0.10);
  border-color: rgba(77, 217, 255, 0.55);
  box-shadow: 0 0 14px rgba(77, 217, 255, 0.30);
  transform: translateY(-1px);
}

.bladeChip:hover .bladeChipDot {
  background: var(--cyan);
  box-shadow: 0 0 8px var(--cyan), 0 0 0 2px rgba(77, 217, 255, 0.20);
}

/* Active blade — amber glow, slightly larger, gentle pulse */

.bladeChip.active {
  color: #ffd9a8;
  background: linear-gradient(180deg,
    rgba(255, 156, 64, 0.18) 0%,
    rgba(255, 156, 64, 0.06) 100%);
  border-color: rgba(255, 156, 64, 0.85);
  box-shadow:
    0 0 16px rgba(255, 156, 64, 0.55),
    0 0 32px rgba(255, 156, 64, 0.25),
    inset 0 0 12px rgba(255, 156, 64, 0.18);
  text-shadow: 0 0 10px rgba(255, 156, 64, 0.70);
  transform: translateY(-1px) scale(1.06);
  animation: bladePulse 2.4s ease-in-out infinite;
}

.bladeChip.active strong {
  color: #ffb273;
  text-shadow:
    0 0 10px rgba(255, 156, 64, 0.85),
    0 0 22px rgba(255, 156, 64, 0.40);
}

.bladeChip.active .bladeChipDot {
  background: #ffb273;
  box-shadow:
    0 0 10px rgba(255, 156, 64, 0.90),
    0 0 0 3px rgba(255, 156, 64, 0.25);
  transform: scale(1.15);
}

.bladeChip.active:hover {
  transform: translateY(-1px) scale(1.08);
  box-shadow:
    0 0 22px rgba(255, 156, 64, 0.70),
    0 0 40px rgba(255, 156, 64, 0.30),
    inset 0 0 12px rgba(255, 156, 64, 0.20);
}

@keyframes bladePulse {
  0%, 100% {
    box-shadow:
      0 0 16px rgba(255, 156, 64, 0.55),
      0 0 32px rgba(255, 156, 64, 0.25),
      inset 0 0 12px rgba(255, 156, 64, 0.18);
  }
  50% {
    box-shadow:
      0 0 22px rgba(255, 156, 64, 0.75),
      0 0 44px rgba(255, 156, 64, 0.35),
      inset 0 0 14px rgba(255, 156, 64, 0.22);
  }
}

.sysId {
  display: flex;
  flex-direction: column;
  font-family: "Share Tech Mono", monospace;
}

.sysId.right { text-align: right; align-items: flex-end; }

.brandSys {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 4px 10px;
  width: 100%;
}

/* === MISSION CHIP (top-right HUD) ======================================== */

/* Anonymized inspection summary that mirrors the brand box on the left in
   shape and footprint. HUD-aesthetic, no live data. */

.missionSys {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 12px;
  width: 100%;
  font-family: "Share Tech Mono", monospace;
}

/* Reserve clearance on the first (date) row so the fixed top-right language
   toggle never overlaps the inspection DATE chip. Only the header row needs it;
   the GPS line below sits clear of the toggle's height. Sized to the compact
   toggle pill (~70px) plus its corner margin, with extra room at the narrow
   breakpoint where the mission column is tighter. */

.missionSys .missionHead {
  padding-right: 84px;
}

.missionHead {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 10px;
  letter-spacing: 0.22em;
}

.missionDot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #6dffb0;
  box-shadow:
    0 0 6px rgba(109, 255, 176, 0.85),
    0 0 14px rgba(109, 255, 176, 0.45);
  animation: missionPulse 2.4s ease-in-out infinite;
}

@keyframes missionPulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}

.missionLabel {
  color: var(--cyan);
  text-shadow: 0 0 6px rgba(77, 217, 255, 0.55);
}

.missionDate {
  /* Replaces the old ON SITE pill: shows the inspection date pulled from the
     DJI photo metadata, right-aligned in the header row. */
  margin-left: auto;
  font-family: "Share Tech Mono", monospace;
  color: var(--cyan);
  text-shadow: 0 0 5px rgba(77, 217, 255, 0.45);
  font-size: 10.5px;
  letter-spacing: 0.18em;
  padding: 1px 7px;
  border: 1px solid rgba(77, 217, 255, 0.32);
  border-radius: 3px;
  background: rgba(77, 217, 255, 0.05);
  line-height: 1.3;
}

.missionId {
  font-family: "Orbitron", "Share Tech Mono", monospace;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.10em;
  color: #ffb273;
  text-shadow:
    0 0 8px rgba(255, 156, 64, 0.55),
    0 0 18px rgba(255, 156, 64, 0.20);
  line-height: 1;
}

/* GPS coords variant: yellow glow, sized to read at a glance, indented so
   its first digit lines up with the "M" of MISSION above (dot 7px + gap
   8px = 15px offset in the header). */

.missionId.missionIdGps {
  font-family: "Share Tech Mono", monospace;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.08em;
  white-space: nowrap;
  padding-left: 15px;
  color: #ffe45e;
  text-shadow:
    0 0 8px rgba(255, 228, 94, 0.65),
    0 0 18px rgba(255, 228, 94, 0.28);
}

.missionMeta {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px 8px;
}

.missionMetaCell {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 3px 6px;
  border: 1px solid rgba(77, 217, 255, 0.18);
  border-radius: 3px;
  background: rgba(8, 26, 42, 0.55);
}

.missionMetaCell span {
  font-size: 9px;
  letter-spacing: 0.18em;
  color: var(--text-dim);
}

.missionMetaCell strong {
  font-size: 11px;
  letter-spacing: 0.10em;
  color: var(--text);
  font-weight: 600;
}

/* Vector brand lockup: three turbines + sparkle on the left, sharp wordmark
   on the right. Scales infinitely, no pixelation. */

.brandLockup {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: 100%;
  color: #ffffff;
}

/* When the lockup is also an <a>, behave like a clickable HUD element. */

a.brandLink {
  text-decoration: none;
  cursor: pointer;
  transition: filter 0.18s ease, transform 0.18s ease;
}

a.brandLink:hover,
a.brandLink:focus-visible {
  filter: drop-shadow(0 0 8px rgba(77, 217, 255, 0.6))
          drop-shadow(0 0 18px rgba(77, 217, 255, 0.25));
  transform: translateY(-0.5px);
  outline: none;
}

.brandMark {
  /* F.AI logo — square asset, sized to match the wordmark cap-height. */
  width: 68px;
  height: 68px;
  object-fit: contain;
  flex: 0 0 auto;
  filter:
    drop-shadow(0 0 8px rgba(77, 217, 255, 0.308))
    drop-shadow(0 0 20px rgba(77, 217, 255, 0.123));
}

.brandWord {
  font-family: "Orbitron", "Share Tech Mono", monospace;
  font-weight: 600;
  /* Sized for the two-word "Blades Inspection" lockup. */
  font-size: 38px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding-left: 0.10em;
  color: #ffffff;
  text-shadow:
    0 0 6px rgba(255, 255, 255, 0.7),
    0 0 26px rgba(77, 217, 255, 0.55),
    0 0 48px rgba(77, 217, 255, 0.25);
  line-height: 1.05;
  max-width: 8.5em;
  white-space: normal;
  word-spacing: 0.05em;
}

/* .brandTagline removed — logo now contains its own visual identity */

.sysId span { font-size: 13px; color: var(--cyan); letter-spacing: 0.18em; }

.sysId span .accent { color: #ffb273; text-shadow: 0 0 6px rgba(255, 156, 64, 0.45); }

.sysId small {
  font-size: 10px;
  color: var(--text-dim);
  letter-spacing: 0.2em;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 2px;
}

/* Right-hand SYS-ID box — full live turbine spec sheet. Reflects whatever
   model is currently selected (or supplied by uploaded inspection data). */

.turbineSysId {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  text-align: left;
  gap: 5px;
  padding: 6px 4px 6px 6px;
  width: 100%;
  min-width: 0;
}

.turbineSysHead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.turbineSysLabel {
  font-family: "Share Tech Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.32em;
  color: var(--cyan-soft);
  text-transform: uppercase;
}

.turbineSysBadge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 7px;
  font-family: "Share Tech Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.22em;
  border-radius: 2px;
}

.turbineSysBadge.isOffshore {
  background: rgba(77, 217, 255, 0.15);
  border: 1px solid rgba(77, 217, 255, 0.55);
  color: #4dd9ff;
  text-shadow: 0 0 6px rgba(77, 217, 255, 0.5);
}

.turbineSysBadge.isOnshore {
  background: rgba(255, 178, 115, 0.15);
  border: 1px solid rgba(255, 178, 115, 0.55);
  color: #ffb273;
  text-shadow: 0 0 6px rgba(255, 156, 64, 0.45);
}

.turbineSysName {
  font-family: "Orbitron", "Share Tech Mono", monospace;
  font-weight: 600;
  font-size: 12px;
  /* Tightened from 0.04em → 0.01em so long model names like
     "SIEMENS GAMESA SG 8.0-167 DD" have more horizontal room before
     AutoFitName has to shrink the font. */
  letter-spacing: 0.01em;
  color: #ffb273;
  text-shadow: 0 0 8px rgba(255, 156, 64, 0.5);
  line-height: 1.18;
  /* Always render the full model name on a single line. The parent block
     is right-aligned (text-align: right on .sysId.right), but for the
     name itself we want the text to start from the left edge of the
     available width so long names like SIEMENS GAMESA SG 14-222 DD have
     the full column to fit without wrapping. */
  display: block;
  width: 100%;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: clip;
}

.turbineSysSpecs {
  display: grid;
  /* Tighter first column, slightly wider last column so SWEPT AREA can fit
     its full number on one line. Tuned for the 320px right-column width. */
  grid-template-columns: 1fr 1fr 1fr 1.25fr;
  gap: 3px 6px;
  margin-top: 4px;
}

.turbineSpecCell {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 3px 6px;
  background: rgba(77, 217, 255, 0.04);
  border-left: 1px solid rgba(77, 217, 255, 0.25);
  border-radius: 1px;
  min-width: 0;
}

.turbineSpecCell span {
  font-family: "Share Tech Mono", monospace;
  font-size: 8px;
  letter-spacing: 0.16em;
  color: var(--text-dim);
  text-transform: uppercase;
  /* Single-line label — never wrap "SWEPT AREA" onto two lines */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: clip;
}

.turbineSpecCell strong {
  font-family: "Share Tech Mono", monospace;
  font-size: 10.5px;
  letter-spacing: 0.04em;
  color: #e9faff;
  white-space: nowrap;
  overflow: visible;
}

/* When the TURBINE MODEL panel sits in the left column (under TURBINE ASSET),
   the column is narrower (280px) than the original top-right slot. Reflow
   the spec grid to 2 columns so labels and values keep room to breathe. */

.turbineSysIdLeft .turbineSysSpecs {
  grid-template-columns: 1fr 1fr;
  gap: 4px 6px;
}

.turbineSysIdLeft {
  padding: 4px 6px 6px;
}

.turbineSysIdLeft .turbineSysName {
  font-size: 13px;
  margin-top: 2px;
}

/* Embedded variant — the TURBINE MODEL spec sheet now lives INSIDE the
   TURBINE ASSET panel (no separate frame). Gets a divider line above it
   and a bit of breathing room so it reads as a distinct section. */

.turbineSysIdEmbedded {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px dashed rgba(77, 217, 255, 0.22);
}

/* === MAIN GRID =========================================================== */

.mainGrid {
  flex: 1;
  display: grid;
  grid-template-columns: 280px 1fr 320px;
  gap: 12px;
  min-height: 0;
}

.leftCol, .rightCol {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
  /* No scrollbar — the side columns are sized to fit their intrinsic content
     within the viewport. Removed the thin cyan track that was showing on the
     right column. */
  overflow: visible;
}

/* Every panel in the side columns shares the column height proportionally,
   so the column totals exactly match the center column — no scroll, no gap. */

.leftCol > .hudFrame,
.rightCol > .hudFrame {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.leftCol > .hudFrame > *:last-child,
.rightCol > .hudFrame > *:last-child {
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

/* Right column: TRACKING → TIMING → WEATHER. All three panels size to their
   intrinsic content so there is no padded empty space at the bottom of any
   panel. The pass list now only shows the 4 passes of the active blade,
   so TRACKING no longer needs a forced min-height. */

.rightCol > .hudFrame:nth-child(1) { flex: 0 0 auto; }

/* TRACKING — intrinsic */

.rightCol > .hudFrame:nth-child(2) { flex: 0 0 auto; }

/* TIMING — intrinsic */

.rightCol > .hudFrame:nth-child(3) { flex: 0 0 auto; }

/* WEATHER — intrinsic */

/* The MISSION chip in topRow is shorter than the centered titleBlock, so the
   mainGrid (which starts below the tallest topRow item) leaves an apparent
   gap on the right side between the MISSION chip and TRACKING RESULTS. Lift
   the rightCol up by ~the height difference so TRACKING sits flush below the
   MISSION chip. Apply the same lift to leftCol so the brand box → INSPECTION
   DATA gap mirrors the right-side MISSION → TRACKING gap exactly.

   The right column carries an extra lift on top because its content
   (TRACKING + TIMING + WEATHER stamps) is taller than the available
   viewport — without this extra pull-up the OBSERVED row at the bottom of
   the WEATHER panel gets clipped under the page fold. Both lifts together
   reclaim ~115px of the empty space that sits between the MISSION chip and
   TRACKING so every weather field stays in view. */

.leftCol {
  margin-top: -42px;
}

/* rightCol needs more lift than leftCol because:
   1) we want the gap between the MISSION chip and TRACKING RESULTS to feel
      like the 10px inter-panel gap (not the larger header→column gap on
      the left), so it reads as part of the same column rhythm.
   2) the right column's content stack (TRACKING + TIMING + WEATHER with
      its 8-row spec grid + OBSERVED footer) is taller than the available
      viewport — without enough lift the OBSERVED row clips off the bottom.
   -65px hits the sweet spot: top gap matches column rhythm, OBSERVED
   stays visible, WEATHER bottom stays roughly aligned with INSPECTION
   PLATFORM on the left. */

.rightCol {
  margin-top: -65px;
}

/* Left column order: INSPECTION DATA → TURBINE ASSET (with embedded
   TURBINE MODEL spec sheet) → INSPECTION PLATFORM. TURBINE ASSET is the
   stretchy one and its embedded spec sheet absorbs all remaining vertical
   room, so there is no empty space inside it. */

.leftCol > .hudFrame:nth-child(1) {                   /* INSPECTION DATA */
  flex: 0 0 auto;
  overflow: visible;
}

.leftCol > .hudFrame:nth-child(2) {                   /* TURBINE ASSET */
  flex: 1 1 auto;
  overflow: visible;
}

.leftCol > .hudFrame:nth-child(3) {                   /* INSPECTION PLATFORM */
  flex: 0 0 auto;
  overflow: visible;
}

.centerCol {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 0;
}

/* === PANEL HEAD ========================================================== */

.panelHead {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: "Share Tech Mono", monospace;
  font-size: 11px;
  letter-spacing: 0.22em;
  color: var(--cyan);
  padding-bottom: 6px;
  margin-bottom: 8px;
  border-bottom: 1px solid var(--cyan-faint);
  text-shadow: 0 0 6px rgba(77, 217, 255, 0.55), 0 0 14px rgba(77, 217, 255, 0.18);
}

/* === ACCESS BODY ========================================================= */

.accessBody p {
  margin: 0 0 8px;
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--text-dim);
}

.accessBody em {
  font-style: normal;
  color: #6dffb0;
  text-shadow: 0 0 8px rgba(109, 255, 176, 0.5);
}

.kv {
  display: flex;
  justify-content: space-between;
  font-family: "Share Tech Mono", monospace;
  font-size: 11px;
  padding: 3px 0;
  border-bottom: 1px dashed rgba(77, 217, 255, 0.12);
}

.kv:last-child { border-bottom: 0; }

.kv span { color: var(--text-dim); letter-spacing: 0.16em; }

.kv strong { color: var(--text); font-weight: 600; }

.kv strong.ok { color: #6dffb0; }

/* === PASS LIST =========================================================== */

.passList { display: flex; flex-direction: column; gap: 3px; }

/* Inspection Sequence panel must always show all 4 passes — never shrink */

.leftCol > .hudFrame.inspectionSeqFrame {
  flex: 0 0 auto;
  overflow: visible;
}

.passRow {
  display: grid;
  grid-template-columns: 10px 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 5px 9px;
  background: rgba(77, 217, 255, 0.04);
  border: 1px solid rgba(77, 217, 255, 0.12);
  border-left: 3px solid var(--pass-color);
  color: var(--text);
  cursor: pointer;
  transition: background 0.2s, border-color 0.2s;
  text-align: left;
}

.passRow:hover { background: rgba(77, 217, 255, 0.08); }

.passRow.active {
  background: rgba(77, 217, 255, 0.12);
  border-color: var(--pass-color);
  box-shadow: 0 0 14px rgba(77, 217, 255, 0.15), inset 0 0 0 1px var(--pass-color);
}

.passRow.done { opacity: 0.55; }

.passDot {
  width: 8px;
  height: 8px;
  background: var(--pass-color);
  border-radius: 50%;
  box-shadow: 0 0 8px var(--pass-color);
}

.passLabel { display: flex; flex-direction: column; line-height: 1.05; }

.passLabel strong {
  font-family: "Share Tech Mono", monospace;
  font-size: 11px;
  letter-spacing: 0.18em;
  color: var(--pass-color);
}

.passLabel small {
  font-size: 9px;
  letter-spacing: 0.08em;
  color: var(--text-dim);
  margin-top: 1px;
}

.passState {
  font-family: "Share Tech Mono", monospace;
  font-size: 10px;
  color: var(--text);
  letter-spacing: 0.12em;
}

/* === STATS GRID ========================================================== */

.statsGrid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
}

.stat {
  display: flex;
  flex-direction: column;
  padding: 6px 8px;
  background: rgba(77, 217, 255, 0.05);
  border: 1px solid rgba(77, 217, 255, 0.12);
}

.stat span {
  font-family: "Share Tech Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.18em;
  color: var(--text-dim);
}

.stat strong {
  font-size: 14px;
  color: var(--cyan);
  font-weight: 600;
  margin-top: 2px;
  text-shadow: 0 0 8px rgba(77, 217, 255, 0.35);
}

/* === PLATFORM PANEL ====================================================== */

.platformPanel {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 0;
}

.platformRow {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}

/* SITE row: single-line "INSPECTION SITE" name + status badge,
   baselines aligned so the pill sits flush with the name. */

.platformRowSite {
  align-items: center;
}

.platformSiteName {
  font-family: "Share Tech Mono", monospace;
  font-size: 11px;
  letter-spacing: 0.10em;
  color: var(--cyan);
  text-shadow: 0 0 8px rgba(77, 217, 255, 0.35);
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  flex: 1 1 auto;
}

.platformLabel {
  display: flex;
  flex-direction: column;
  line-height: 1.15;
}

.platformLabel span {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: "Share Tech Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.22em;
  color: var(--text-dim);
}

.platformLabel strong {
  font-family: "Share Tech Mono", monospace;
  font-size: 11px;
  letter-spacing: 0.10em;
  color: var(--cyan);
  margin-top: 2px;
  text-shadow: 0 0 8px rgba(77, 217, 255, 0.35);
  line-height: 1.2;
}

.platformLabel small {
  font-size: 9px;
  letter-spacing: 0.08em;
  color: var(--text-dim);
  margin-top: 1px;
  line-height: 1.2;
}

/* Turbine model name: always one line. Long names auto-shrink to fit
   the available width, with ellipsis as a last resort. */

.modelLabel {
  min-width: 0;
  flex: 1 1 auto;
  overflow: hidden;
}

.modelName {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 9.5px;
  letter-spacing: 0.04em;
  max-width: 100%;
}

.platformBadge {
  align-self: flex-start;
  font-family: "Share Tech Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.22em;
  color: #03070d;
  background: var(--cyan);
  padding: 2px 6px;
  box-shadow: 0 0 8px var(--cyan);
}

.platformBadge.badgeWarn {
  background: #ffb273;
  box-shadow: 0 0 8px rgba(255, 156, 64, 0.85);
}

.platformBadge.badgeAlert {
  background: #ff7a3d;
  box-shadow: 0 0 8px rgba(255, 122, 61, 0.85);
}

/* "Observed at YYYY-MM-DD HH:MM UTC" footer for the weather panel — small,
   monospace, dim, sits below the spec grid. */

.weatherStamp {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 6px;
  padding-top: 5px;
  border-top: 1px dashed rgba(77, 217, 255, 0.18);
  font-family: "Share Tech Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.18em;
}

.weatherStamp span { color: var(--text-dim); }

.weatherStamp strong { color: var(--cyan); font-weight: 600; text-shadow: 0 0 6px rgba(77, 217, 255, 0.4); }

.platformSpecs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3px 6px;
  margin-top: 2px;
}

.specRow {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 6px;
  font-family: "Share Tech Mono", monospace;
  font-size: 9.5px;
  letter-spacing: 0.06em;
  padding: 3px 5px;
  background: rgba(77, 217, 255, 0.04);
  border-left: 1px solid var(--cyan-faint);
  white-space: nowrap;
  overflow: hidden;
}

.specRow span {
  color: var(--text-dim);
  text-overflow: ellipsis;
  overflow: hidden;
}

.specRow strong {
  color: var(--cyan);
  text-shadow: 0 0 6px rgba(77, 217, 255, 0.4);
  flex-shrink: 0;
}

.specRow span { color: var(--text-dim); }

.specRow strong { color: var(--text); font-weight: 600; }

.platformDivider {
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--cyan-faint), transparent);
  margin: 2px 0;
}

/* === CENTER: BLADES ROW ================================================== */

.bladesRow {
  flex: 1;
  display: grid;
  /* Right (inspection feed) is 40px wider than left (wireframe stage).
     Math: gap=12px; left=(100% - 52px)/2; right=1fr fills the remainder,
     which works out to left + 40px. */
  grid-template-columns: calc((100% - 52px) / 2) 1fr;
  gap: 12px;
  min-height: 0;
}

.bladesRow > .hudFrame {
  display: flex;
  flex-direction: column;
  padding: 8px;
  min-height: 0;
}

.bladeLabel {
  font-family: "Share Tech Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.22em;
  color: var(--cyan);
  padding: 4px 6px;
  border-bottom: 1px solid var(--cyan-faint);
  margin-bottom: 6px;
  text-align: center;
}

.bladeStage {
  flex: 1;
  position: relative;
  min-height: 0;
  overflow: hidden;
  background:
    radial-gradient(ellipse 70% 90% at 50% 55%, rgba(77, 217, 255, 0.07), transparent 70%),
    linear-gradient(180deg, rgba(8, 18, 30, 0.4), rgba(2, 6, 12, 0.0));
}

/* Pass progress overlay inside the wireframe stage — bare number, no chrome */

.passProgressOverlay {
  position: absolute;
  left: 14px;
  bottom: 12px;
  pointer-events: none;
  z-index: 4;
  font-family: "Orbitron", "Share Tech Mono", monospace;
  font-weight: 600;
  /* Shrunk to ~60% of the prior 28px so the overlay reads as a HUD chip
     rather than dominating the scene. */
  font-size: 17px;
  line-height: 1;
  letter-spacing: 0.04em;
  color: var(--pass-color, var(--cyan));
  text-shadow: 0 0 8px rgba(77, 217, 255, 0.45);
}

/* === STAGE INTERACTIVE (click-to-play) =================================== */

/* Both the left wireframe stage and the right photoreal stage are wrapped
   in a button-like element that toggles play/pause on click. */

.stageInteractive {
  cursor: pointer;
  user-select: none;
  outline: none;
}

.stageInteractive:focus-visible {
  box-shadow: inset 0 0 0 2px rgba(77, 217, 255, 0.55);
}

.stageWrap {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
}

.stageWrap > * {
  flex: 1;
  min-height: 0;
}

.stagePlayHint {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) scale(0.92);
  width: 72px;
  height: 72px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(3, 8, 14, 0.55);
  color: #ffd9a8;
  border: 1px solid rgba(255, 156, 64, 0.55);
  box-shadow:
    0 0 20px rgba(255, 156, 64, 0.35),
    inset 0 0 14px rgba(255, 156, 64, 0.18);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.22s ease, transform 0.22s ease, box-shadow 0.22s ease;
  z-index: 6;
  backdrop-filter: blur(2px);
}

.stagePlayHint svg {
  filter: drop-shadow(0 0 6px rgba(255, 156, 64, 0.70));
}

.stageInteractive:hover .stagePlayHint {
  opacity: 0.95;
  transform: translate(-50%, -50%) scale(1);
}

.stageInteractive:active .stagePlayHint {
  transform: translate(-50%, -50%) scale(0.94);
  box-shadow:
    0 0 28px rgba(255, 156, 64, 0.55),
    inset 0 0 16px rgba(255, 156, 64, 0.25);
}

/* Holographic CRT-style scanlines */

.bladeStage::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(
    180deg,
    rgba(77, 217, 255, 0.045) 0px,
    rgba(77, 217, 255, 0.045) 1px,
    transparent 1px,
    transparent 3px
  );
  mix-blend-mode: screen;
  pointer-events: none;
  z-index: 2;
}

/* Holographic scan sweep — a single hairline filament with a barely-there
   halo. Tuned to be felt rather than seen; a slow, near-invisible sensor
   pass that lifts the wireframe slightly as it crosses. */

.bladeStage::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg,
    transparent 0%,
    transparent 49.5%,
    rgba(180, 240, 255, 0.018) 49.85%,  /* faint pre-glow */
    rgba(210, 250, 255, 0.045) 49.97%,  /* hairline core */
    rgba(210, 250, 255, 0.045) 50.03%,
    rgba(180, 240, 255, 0.018) 50.15%,  /* faint post-glow */
    transparent 50.5%,
    transparent 100%);
  background-size: 100% 240%;
  mix-blend-mode: screen;
  pointer-events: none;
  z-index: 3;
  animation: holoSweep 8s linear infinite;
}

@keyframes holoSweep {
  0%   { background-position-y: -120%; }
  100% { background-position-y: 120%; }
}

.sceneMount {
  position: absolute;
  inset: 0;
}

.sceneMount canvas {
  display: block;
  width: 100% !important;
  height: 100% !important;
}

/* Static wireframe blade image — one per pass (te/ps/le/ss), same image
   regardless of turbine model or upload. Sized to occupy the same vertical
   fraction as the photoreal panel on the right (96%) so root and tip line
   up across the two panels. */

.bladeWireframeImg {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  height: 96%;
  width: auto;
  max-width: 96%;
  object-fit: contain;
  pointer-events: none;
  user-select: none;
  filter: drop-shadow(0 0 18px rgba(77, 217, 255, 0.245))
          drop-shadow(0 0 4px rgba(77, 217, 255, 0.35));
}

/* Crossfade layers — all four wireframes are mounted; only the active
   one is fully visible. Inactive layers fade out (slightly scaled down
   with a faint blur) so the transition reads as a holographic dissolve
   rather than a hard image swap. */

.bladeWireframeLayer {
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.985);
  filter: drop-shadow(0 0 18px rgba(77, 217, 255, 0.245))
          drop-shadow(0 0 4px rgba(77, 217, 255, 0.35))
          blur(2px);
  transition:
    opacity 0.55s ease,
    transform 0.55s ease,
    filter 0.55s ease;
}

.bladeWireframeLayer.isActive {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
  filter: drop-shadow(0 0 18px rgba(77, 217, 255, 0.245))
          drop-shadow(0 0 4px rgba(77, 217, 255, 0.35))
          blur(0);
}

/* Orbit rings around wireframe base */

.orbitRings {
  position: absolute;
  left: 50%;
  bottom: 14%;
  transform: translateX(-50%);
  width: 180px;
  height: 50px;
  pointer-events: none;
  perspective: 400px;
}

.orbitRings span {
  position: absolute;
  inset: 0;
  border: 1px solid rgba(77, 217, 255, 0.4);
  border-radius: 50%;
  transform: rotateX(72deg) scale(1);
  animation: pulseRing 3s ease-out infinite;
}

.orbitRings span:nth-child(2) { animation-delay: 1s; }

.orbitRings span:nth-child(3) { animation-delay: 2s; }

@keyframes pulseRing {
  0% { transform: rotateX(72deg) scale(0.3); opacity: 0.8; }
  100% { transform: rotateX(72deg) scale(1.4); opacity: 0; }
}

/* === PHOTOREAL VIEW ====================================================== */

.photorealStage {
  flex: 1;
  position: relative;
  min-height: 0;
  overflow: hidden;
  background:
    radial-gradient(ellipse 60% 80% at center, rgba(30, 70, 110, 0.25), transparent 70%);
}

.photorealBlade {
  position: absolute;
  top: 50%;
  left: 50%;
  height: 96%;
  width: auto;
  transform: translate(-50%, -50%);
  opacity: 0;
  transition: opacity 0.6s ease;
  filter: drop-shadow(0 0 18px rgba(77, 217, 255, 0.35)) drop-shadow(0 6px 32px rgba(0, 0, 0, 0.6));
  pointer-events: none;
}

.photorealBlade.active { opacity: 1; }

.photorealOverlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.photorealLabel {
  position: absolute;
  top: 8px;
  right: 8px;
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: "Share Tech Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.18em;
  color: var(--pass-color);
  background: rgba(0, 0, 0, 0.5);
  padding: 4px 8px;
  border: 1px solid var(--pass-color);
}

.photorealLabel .dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--pass-color);
  box-shadow: 0 0 8px var(--pass-color);
}

/* === CONTROL DECK ======================================================== */

.controlDeck {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 4px 6px;
}

.scrubLabel {
  display: flex;
  justify-content: space-between;
  font-family: "Share Tech Mono", monospace;
  font-size: 11px;
  letter-spacing: 0.18em;
  color: var(--text-dim);
}

.scrubLabel strong { color: var(--cyan); }

.scrubber {
  position: relative;
  height: 6px;
  background: rgba(77, 217, 255, 0.08);
  border: 1px solid rgba(77, 217, 255, 0.2);
  overflow: hidden;
}

.scrubberFill {
  height: 100%;
  background: linear-gradient(90deg, var(--cyan), #fff);
  box-shadow: 0 0 12px var(--cyan);
  transition: width 0.1s linear;
}

.scrubTick {
  position: absolute;
  top: -3px;
  width: 1px;
  height: 12px;
  background: var(--cyan-soft);
}

.controls {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 8px;
}

.controlsCenter {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  grid-column: 2;
}

.ctrlBtn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  background: rgba(77, 217, 255, 0.06);
  border: 1px solid var(--cyan-soft);
  color: var(--cyan);
  font-family: "Share Tech Mono", monospace;
  font-size: 11px;
  letter-spacing: 0.18em;
  cursor: pointer;
  transition: all 0.18s ease;
  text-transform: uppercase;
  min-height: 34px;
}

.ctrlBtn:hover {
  background: rgba(77, 217, 255, 0.18);
  border-color: var(--cyan);
  box-shadow: 0 0 10px rgba(77, 217, 255, 0.45);
  color: #e9faff;
}

.ctrlBtn.isActive {
  background: var(--cyan);
  color: #03070d;
  border-color: var(--cyan);
  box-shadow: 0 0 16px var(--cyan);
}

.ctrlBtn.primary {
  border-color: #ffb273;
  color: #ffb273;
}

.ctrlBtn.primary:hover {
  background: rgba(255, 178, 115, 0.15);
  box-shadow: 0 0 10px rgba(255, 178, 115, 0.45);
}

.ctrlBtn.primary.isActive {
  background: #ffb273;
  color: #1a0e02;
  box-shadow: 0 0 18px rgba(255, 178, 115, 0.7);
}

.legend {
  display: flex;
  gap: 12px;
  justify-content: flex-end;
  font-family: "Share Tech Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.15em;
  grid-column: 3;
}

.legend span {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--c);
}

.legend i {
  width: 18px;
  height: 2px;
  background: var(--c);
  box-shadow: 0 0 6px var(--c);
}

/* === RIGHT COL: MERGED INSPECTION FEED =================================== */

.recDot {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: "Share Tech Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.22em;
  color: #ff7a3d;
}

.recDot i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #ff7a3d;
  box-shadow: 0 0 8px #ff7a3d;
  animation: recPulse 1.2s ease-in-out infinite;
}

@keyframes recPulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.25; }
}

.feedPanel {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 0;
  flex: 1;
}

.feedCurrent {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  background: #0a1118;
  border: 1px solid var(--pass-color);
  box-shadow:
    0 0 0 1px rgba(77, 217, 255, 0.1),
    0 0 24px rgba(77, 217, 255, 0.18);
}

.feedPanel { flex: 1; min-height: 0; }

.feedFrame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* `cover` fills the panel edge-to-edge — no black bands at the top/bottom.
     Some photos may have parts cropped; the viewer can click the frame to
     open the full image in the lightbox where everything is visible. */
  object-fit: cover;
  display: block;
  opacity: 0;
  transition: opacity 120ms linear;
}

.feedFrameActive {
  opacity: 1;
}

.feedHud {
  position: absolute;
  inset: 0;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 6px 8px;
}

.liveTag {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: "Share Tech Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.22em;
  /* Brighter orange — pushed toward a more luminous tone with stronger
     glow so the LIVE badge reads as the most active element in the feed. */
  color: #ffa168;
  background: rgba(0, 0, 0, 0.56);
  border: 1px solid #ffa168;
  padding: 2px 6px;
  box-shadow: 0 0 10px rgba(255, 161, 104, 0.55);
  text-shadow: 0 0 6px rgba(255, 161, 104, 0.85);
}

.liveTag i {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #ffa168;
  box-shadow: 0 0 8px #ffa168;
  animation: recPulse 1.2s ease-in-out infinite;
}

/* Single-line badge variant — merges LIVE + pass + frame counter into one
   bordered chip so the HUD overlay reads as a single status line. */

.liveTagInline {
  white-space: nowrap;
}

.liveTagInline .liveSep {
  opacity: 0.55;
  margin: 0 2px;
}

.feedFrameId {
  align-self: flex-start;
  font-family: "Share Tech Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.18em;
  background: rgba(0, 0, 0, 0.7);
  border: 1px solid var(--pass-color);
  color: var(--pass-color);
  padding: 2px 7px;
  box-shadow: 0 0 10px color-mix(in srgb, var(--pass-color) 35%, transparent);
  text-shadow: 0 0 5px color-mix(in srgb, var(--pass-color) 70%, transparent);
}

/* Live drone-to-blade standoff distance, derived from DJI XMP GPS at
   resample time. Minimalist holographic chip: single hairline frame,
   cut corners, one live dot, fixed-width numeric slot so the chip
   never resizes as the value updates. */

.feedDistance {
  position: relative;
  align-self: flex-end;
  margin-top: auto;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: "Share Tech Mono", monospace;
  letter-spacing: 0.22em;
  background: rgba(0, 14, 26, 0.55);
  /* Angled cut-corner silhouette — sci-fi nameplate. */
  clip-path: polygon(
    6px 0,
    calc(100% - 6px) 0,
    100% 6px,
    100% calc(100% - 6px),
    calc(100% - 6px) 100%,
    6px 100%,
    0 calc(100% - 6px),
    0 6px
  );
  color: #4dd9ff;
  padding: 4px 12px;
}

/* Single hairline frame matching the clip silhouette. */

.feedDistance::before {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid rgba(77, 217, 255, 0.45);
  clip-path: inherit;
  pointer-events: none;
}

/* Small steady live dot — no pulse, no halo. */

.feedDistancePulse {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #4dd9ff;
  box-shadow: 0 0 4px rgba(77, 217, 255, 0.7);
  flex: 0 0 auto;
}

/* Hairline divider between label and value. */

.feedDistanceSep {
  width: 1px;
  height: 11px;
  background: rgba(77, 217, 255, 0.5);
  flex: 0 0 auto;
}

.feedDistanceLabel {
  color: #cfeefb;
  letter-spacing: 0.30em;
  font-size: 9.5px;
  text-transform: uppercase;
}

.feedDistanceValue {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  font-weight: 700;
  letter-spacing: 0.04em;
}

/* Fixed-width numeric slot so the chip width is invariant as the value
   changes. Tabular-nums lock each digit to the same advance; the slot
   itself is sized to fit "00.00". */

.feedDistanceNum {
  color: #ffd966;
  font-size: 14px;
  font-family: "Orbitron", "Share Tech Mono", monospace;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  display: inline-block;
  min-width: 4.2ch;
  text-align: right;
  text-shadow: 0 0 4px rgba(255, 217, 102, 0.55);
}

.feedDistanceUnit {
  color: #4dd9ff;
  font-size: 10px;
  letter-spacing: 0.25em;
  text-shadow: 0 0 3px rgba(77, 217, 255, 0.45);
}

.feedScan {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(180deg, transparent 0%, rgba(77, 217, 255, 0.35) 50%, transparent 100%);
  background-size: 100% 12px;
  opacity: 0.5;
  animation: scanLine 2.4s linear infinite;
  mix-blend-mode: overlay;
}

@keyframes scanLine {
  0% { background-position-y: -100%; }
  100% { background-position-y: 100%; }
}

.feedHistoryHead {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-family: "Share Tech Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.18em;
  color: var(--text-dim);
  border-top: 1px solid var(--cyan-faint);
  padding-top: 6px;
}

.feedTicks {
  display: flex;
  gap: 2px;
}

.feedTicks i {
  display: block;
  width: 6px;
  height: 8px;
  background: rgba(77, 217, 255, 0.12);
  border: 1px solid rgba(77, 217, 255, 0.18);
  transition: background 0.2s;
}

.feedTicks i.on {
  background: var(--cyan);
  box-shadow: 0 0 4px var(--cyan);
}

.filmstrip {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding-right: 4px;
}

.filmstrip::-webkit-scrollbar { width: 4px; }

.filmstrip::-webkit-scrollbar-thumb { background: var(--cyan-soft); }

.filmstrip::-webkit-scrollbar-track { background: rgba(77, 217, 255, 0.06); }

.filmFrame {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border: 1px solid rgba(77, 217, 255, 0.18);
  animation: slideIn 0.4s ease-out;
  flex-shrink: 0;
  opacity: 0.85;
}

.filmFrame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.filmFrame span {
  position: absolute;
  bottom: 2px;
  right: 2px;
  font-family: "Share Tech Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.12em;
  background: rgba(0, 0, 0, 0.7);
  color: var(--cyan);
  padding: 1px 4px;
}

@keyframes slideIn {
  from { opacity: 0; transform: translateY(-12px); }
  to { opacity: 0.85; transform: translateY(0); }
}

.filmEmpty {
  text-align: center;
  font-family: "Share Tech Mono", monospace;
  font-size: 11px;
  color: var(--text-dim);
  padding: 16px 0;
  margin: 0;
}

/* === TRACKERS ============================================================ */

.trackers {
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* Intrinsic height — TRACKING panel hugs its content (4 pass rows of the
     active blade) so there is no padded empty space below the list. The
     TIMING and WEATHER panels below can move up. */
}

.passList {
  flex: 0 0 auto;
}

.trackerHead {
  display: flex;
  justify-content: space-between;
  font-family: "Share Tech Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.16em;
  margin-bottom: 3px;
}

.trackerHead span { color: var(--text-dim); }

.trackerHead strong { color: var(--cyan); font-weight: 600; }

.trackerBar {
  height: 6px;
  background: rgba(77, 217, 255, 0.06);
  border: 1px solid rgba(77, 217, 255, 0.2);
  overflow: hidden;
}

.trackerBar div {
  height: 100%;
  background: linear-gradient(90deg, var(--cyan) 0%, #fff 100%);
  box-shadow: 0 0 8px var(--cyan);
  transition: width 0.5s;
}

.dataIntegrity { margin-top: 6px; }

.trackingSequence {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px solid rgba(77, 217, 255, 0.18);
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.trackingSequenceHead {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: "Share Tech Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.22em;
  color: var(--text-dim);
}

.dataIntegrity span {
  font-family: "Share Tech Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.16em;
  color: var(--text-dim);
}

.waveform {
  display: flex;
  align-items: flex-end;
  gap: 1px;
  height: 60px;
  margin-top: 6px;
  padding: 3px;
  background: rgba(0, 0, 0, 0.4);
  border: 1px solid rgba(77, 217, 255, 0.15);
}

.waveform span {
  flex: 1;
  background: var(--cyan);
  opacity: 0.7;
  min-height: 2px;
  box-shadow: 0 0 4px var(--cyan);
}

/* === RESPONSIVE ========================================================== */

@media (max-width: 1280px) {
  .mainGrid { grid-template-columns: 240px 1fr 280px; }
  .topRow { grid-template-columns: 180px 1fr 200px; }
  /* Tighter mission column — keep the date chip clear of the toggle. */
  .missionSys .missionHead { padding-right: 80px; }
}

/* Mobile-only notice. Rendered (in JSX) ONLY on real mobile devices, so this
   block just styles it — it never appears on desktop. It's a sticky full-width
   bar at the very top; the language toggle is pushed BELOW it (see
   .langToggle--belowNotice) so the two never overlap. */

.mobileOnlyNotice {
  position: sticky;
  top: 0;
  z-index: 99998;
  display: flex;
  align-items: center;
  gap: 10px;
  background: #1e3a8a;
  color: #e8eefb;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 600;
  padding: 10px 12px 10px 14px;
  border-bottom: 1px solid #3b82f6;
}

.mobileOnlyNotice__text { flex: 1; text-align: center; }

/* The × lets a mobile visitor dismiss the notice and keep browsing. */

.mobileOnlyNotice__close {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.12);
  color: #e8eefb;
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 8px;
  font-size: 15px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  font-family: inherit;
}

.mobileOnlyNotice__close:active { background: rgba(255, 255, 255, 0.22); }

/* When the mobile notice is shown, drop the floating language toggle clearly
   beneath the notice bar so it never overlaps the warning text or the × — the
   bar can wrap to two lines on narrow phones, so leave generous clearance. */

.langToggle--belowNotice { top: 66px !important; }

@media (max-width: 1024px) {
  html, body { overflow-y: auto; height: auto; }
  .appShell { height: auto; min-height: 100vh; }
  .mainGrid { grid-template-columns: 1fr; }
  .bladesRow { grid-template-columns: 1fr; }
  .bladeStage, .photorealStage { min-height: 320px; }
}

/* === CLICKABLE FEED + LIGHTBOX =========================================== */

/* .feedCurrent is now a <button> so the live feed is clickable.
   Reset native button styling and add an expand affordance. */

button.feedCurrent {
  appearance: none;
  -webkit-appearance: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  text-align: inherit;
  cursor: pointer;
  display: block;
  width: 100%;
  /* Keep the existing flex sizing rules above */
}

.feedClickable {
  transition: box-shadow 0.18s ease, transform 0.18s ease;
}

.feedClickable:hover {
  box-shadow:
    0 0 0 1px var(--pass-color),
    0 0 22px rgba(77, 217, 255, 0.35);
}

.feedClickable:hover .feedExpand {
  opacity: 1;
  transform: scale(1);
}

.feedExpand {
  position: absolute;
  top: 10px;
  right: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  background: rgba(2, 8, 14, 0.7);
  border: 1px solid var(--cyan-soft);
  color: var(--cyan);
  border-radius: 2px;
  opacity: 0.55;
  transform: scale(0.92);
  transition: all 0.18s ease;
  backdrop-filter: blur(4px);
  pointer-events: none;
  z-index: 6;
}

.lightbox {
  position: fixed;
  inset: 0;
  background: rgba(2, 6, 12, 0.88);
  backdrop-filter: blur(8px);
  z-index: 1000;
  display: grid;
  place-items: center;
  padding: 36px;
  animation: lightboxFade 180ms ease-out;
}

@keyframes lightboxFade {
  from { opacity: 0; }
  to { opacity: 1; }
}

.lightboxStage {
  position: relative;
  max-width: min(92vw, 1500px);
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  background: rgba(8, 16, 26, 0.85);
  border: 1px solid var(--cyan-soft);
  box-shadow:
    0 0 0 1px rgba(77, 217, 255, 0.25),
    0 30px 80px rgba(0, 0, 0, 0.6),
    0 0 40px rgba(77, 217, 255, 0.18);
  padding: 14px;
}

.lightboxImageWrap {
  position: relative;
  width: 100%;
  height: calc(90vh - 90px);
  max-width: 100%;
  overflow: hidden;
  background: #03070c;
  display: grid;
  place-items: center;
}

.lightboxImage {
  display: block;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  background: #03070c;
  will-change: transform;
  user-select: none;
  -webkit-user-drag: none;
}

.lightboxNav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 64px;
  display: grid;
  place-items: center;
  background: rgba(8, 16, 26, 0.78);
  border: 1px solid var(--cyan-soft);
  color: var(--cyan);
  cursor: pointer;
  transition: all 0.18s ease;
  z-index: 3;
}

.lightboxNav:hover:not(:disabled) {
  background: rgba(77, 217, 255, 0.18);
  box-shadow: 0 0 14px rgba(77, 217, 255, 0.45);
  color: #fff;
}

.lightboxNav:disabled {
  opacity: 0.25;
  cursor: not-allowed;
}

.lightboxNavPrev { left: 6px; }

.lightboxNavNext { right: 6px; }

.lightboxZoomCtrl {
  position: absolute;
  bottom: 56px;
  right: 16px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 8px;
  background: rgba(8, 16, 26, 0.85);
  border: 1px solid var(--cyan-soft);
  color: var(--cyan);
  font-family: "Share Tech Mono", monospace;
  font-size: 11px;
  letter-spacing: 0.16em;
  z-index: 3;
}

.lightboxZoomCtrl button {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  background: transparent;
  border: 1px solid var(--cyan-soft);
  color: var(--cyan);
  cursor: pointer;
  transition: all 0.18s ease;
}

.lightboxZoomCtrl button:hover {
  background: rgba(77, 217, 255, 0.18);
  color: #fff;
}

.lightboxZoomCtrl span {
  min-width: 44px;
  text-align: center;
  color: var(--text);
}

.lightboxClose {
  position: absolute;
  top: -1px;
  right: -1px;
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  background: rgba(8, 16, 26, 0.95);
  border: 1px solid var(--cyan-soft);
  color: var(--cyan);
  cursor: pointer;
  transition: all 0.18s ease;
  z-index: 2;
}

.lightboxClose:hover {
  background: #ff7a3d;
  color: #fff;
  border-color: #ff7a3d;
  box-shadow: 0 0 14px rgba(255, 122, 61, 0.55);
}

.lightboxCaption {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 10px 4px 2px;
  width: 100%;
  font-family: "Share Tech Mono", monospace;
  font-size: 12px;
  letter-spacing: 0.20em;
  color: var(--text-dim);
}

.lightboxCaption small {
  margin-left: auto;
  font-size: 10px;
  opacity: 0.7;
  letter-spacing: 0.18em;
}

.lightboxBadge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  background: rgba(255, 178, 115, 0.15);
  border: 1px solid rgba(255, 178, 115, 0.5);
  color: #ffb273;
  font-size: 10px;
  letter-spacing: 0.22em;
}

/* === TURBINE PICKER ====================================================== */

.turbinePicker {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px 12px;
  background: rgba(77, 217, 255, 0.05);
  border: 1px solid rgba(77, 217, 255, 0.18);
  border-radius: 3px;
}

.pickerLabel {
  font-family: "Share Tech Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.24em;
  color: var(--cyan-soft);
  text-transform: uppercase;
}

.pickerSelect,
.pickerInput {
  width: 100%;
  background: rgba(3, 8, 14, 0.9);
  border: 1px solid rgba(77, 217, 255, 0.35);
  color: #e9faff;
  font-family: "Share Tech Mono", monospace;
  font-size: 11px;
  letter-spacing: 0.08em;
  padding: 7px 9px;
  border-radius: 2px;
  outline: none;
  cursor: pointer;
}

.pickerSelect:focus,
.pickerInput:focus {
  border-color: var(--cyan);
  box-shadow: 0 0 8px rgba(77, 217, 255, 0.4);
}

.pickerSelect option {
  background: #03080e;
  color: #e9faff;
}

.customGroup {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 8px;
  padding: 8px 10px;
  border: 1px dashed rgba(77, 217, 255, 0.25);
  background: rgba(77, 217, 255, 0.03);
  border-radius: 3px;
  transition: border-color 0.25s ease, background 0.25s ease, box-shadow 0.25s ease;
}

.customGroup.active {
  border-color: rgba(255, 156, 64, 0.65);
  background: rgba(255, 156, 64, 0.06);
  box-shadow: 0 0 12px rgba(255, 156, 64, 0.20);
}

.customGroup.active .pickerLabel {
  color: #ffb273;
}

.customGroup .pickerInput:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.customSearchRow {
  display: flex;
  align-items: stretch;
  gap: 6px;
}

.customSearchRow .pickerInput {
  flex: 1;
  min-width: 0;
}

.searchBtn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 0 10px;
  font-family: "Share Tech Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.18em;
  color: var(--cyan);
  background: rgba(77, 217, 255, 0.10);
  border: 1px solid rgba(77, 217, 255, 0.55);
  border-radius: 3px;
  cursor: pointer;
  text-transform: uppercase;
  transition: background 0.2s ease, border-color 0.2s ease,
    box-shadow 0.2s ease, color 0.2s ease, transform 0.1s ease;
  white-space: nowrap;
}

.searchBtn:hover:not(:disabled) {
  background: rgba(77, 217, 255, 0.20);
  border-color: var(--cyan);
  color: #ffffff;
  box-shadow: 0 0 12px rgba(77, 217, 255, 0.45);
}

.searchBtn:active:not(:disabled) {
  transform: translateY(1px);
}

.searchBtn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.customGroup.active .searchBtn {
  color: #ffb273;
  background: rgba(255, 156, 64, 0.08);
  border-color: rgba(255, 156, 64, 0.55);
}

.customGroup.active .searchBtn:hover:not(:disabled) {
  background: rgba(255, 156, 64, 0.18);
  border-color: rgba(255, 156, 64, 0.85);
  color: #ffffff;
  box-shadow: 0 0 12px rgba(255, 156, 64, 0.45);
}

.lookupStatus {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 2px;
  padding: 3px 8px;
  font-family: "Share Tech Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.16em;
  color: var(--cyan-soft);
  background: rgba(77, 217, 255, 0.04);
  border-left: 1px solid rgba(77, 217, 255, 0.30);
  border-radius: 2px;
  align-self: flex-start;
  text-transform: uppercase;
}

.lookupStatus.is-searching { color: #9ad5ff; }

.lookupStatus.is-found {
  color: #ffb273;
  background: rgba(255, 156, 64, 0.06);
  border-left-color: rgba(255, 156, 64, 0.65);
  text-shadow: 0 0 6px rgba(255, 156, 64, 0.4);
}

.lookupStatus.is-notfound,
.lookupStatus.is-error { color: rgba(255, 178, 115, 0.85); }

.lookupDot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--cyan);
  box-shadow: 0 0 6px var(--cyan);
  animation: pulseDot 1.2s ease-in-out infinite;
}

.lookupDot.ok {
  background: #ffb273;
  box-shadow: 0 0 6px #ffb273;
  animation: none;
}

.lookupDot.warn {
  background: #b87a4a;
  box-shadow: none;
  animation: none;
}

@keyframes pulseDot {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.35; transform: scale(0.7); }
}

.customRow {
  display: flex;
  align-items: center;
  gap: 8px;
}

.customRow label {
  flex: 1;
  font-family: "Share Tech Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.18em;
  color: var(--cyan-soft);
}

.pickerInput.small {
  width: 80px;
  text-align: right;
}

/* === UPLOAD BLOCK ======================================================== */

.uploadBlock {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-bottom: 4px;
}

.uploadHelp {
  margin: 0;
  font-family: "Share Tech Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.06em;
  color: rgba(220, 239, 255, 0.7);
  line-height: 1.45;
}

.uploadHelp b {
  color: var(--cyan);
  font-weight: 700;
}

.uploadInput {
  display: none;
}

.uploadActions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.uploadStatus {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 8px 10px;
  background: rgba(77, 217, 255, 0.04);
  border: 1px solid rgba(77, 217, 255, 0.15);
  border-radius: 3px;
  font-family: "Share Tech Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.12em;
}

.uploadStatus.muted {
  color: rgba(220, 239, 255, 0.5);
  text-align: center;
}

.uploadRow {
  display: flex;
  justify-content: space-between;
  gap: 8px;
}

.uploadRow span {
  color: var(--cyan-soft);
}

.uploadRow strong {
  color: #e9faff;
}

/* === TIMING HERO ========================================================= */

.timingHero {
  display: flex;
  align-items: stretch;
  gap: 10px;
  padding: 10px 12px;
  margin-bottom: 8px;
  background: rgba(255, 178, 115, 0.08);
  border: 1px solid rgba(255, 178, 115, 0.32);
  border-radius: 3px;
}

.timingHeroItem {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: flex-start;
}

.timingHeroItem span {
  font-family: "Share Tech Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.18em;
  color: rgba(255, 178, 115, 0.85);
  text-transform: uppercase;
  /* Force the label onto a single line — "FULL TURBINE · A+B+C" must never
     wrap to two rows. The label and the duration row stay one-line each. */
  white-space: nowrap;
}

.timingHeroItem strong {
  font-family: "Share Tech Mono", monospace;
  /* Single-line duration — "12 MIN 06 S" / "36 MIN 21 S" must never wrap to
     a second line. Slightly smaller + tighter tracking so even the longest
     full-turbine totals fit comfortably in the column. */
  font-size: 15px;
  letter-spacing: 0.04em;
  color: #ffe1c2;
  white-space: nowrap;
}

.timingHeroItem strong.accent {
  color: #ffb273;
  text-shadow: 0 0 8px rgba(255, 178, 115, 0.55);
}

.timingDivider {
  width: 1px;
  background: rgba(255, 178, 115, 0.3);
}

/* === BLADE TIME ROW =======================================================
   A/B/C running tally + live turbine total under the hero. Four equal cells
   in a horizontal strip. Each cell signals state via the modifier class:
   .bladeTime-done   → completed blade, final duration locked in (green)
   .bladeTime-live   → currently inspecting (cyan, pulsing)
   .bladeTime-idle   → not yet started (muted, em-dash)
   .bladeTime-total  → live turbine A+B+C total (amber accent)            */

.bladeTimeRow {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  margin-bottom: 10px;
}

.bladeTimeCell {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 3px;
  padding: 6px 8px;
  border: 1px solid rgba(77, 217, 255, 0.18);
  background: rgba(8, 20, 30, 0.55);
  border-radius: 2px;
  position: relative;
  overflow: hidden;
}

.bladeTimeCell span {
  font-family: "Share Tech Mono", monospace;
  font-size: 8px;
  letter-spacing: 0.18em;
  color: rgba(180, 220, 240, 0.55);
  text-transform: uppercase;
  white-space: nowrap;
}

.bladeTimeCell strong {
  font-family: "Share Tech Mono", monospace;
  font-size: 11px;
  letter-spacing: 0.04em;
  color: #e9faff;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* DONE — locked in, green confirmation. */

.bladeTime-done {
  border-color: rgba(74, 222, 128, 0.38);
  background: rgba(20, 50, 30, 0.45);
}

.bladeTime-done span { color: rgba(140, 230, 170, 0.80); }

.bladeTime-done strong { color: #c8f4d6; text-shadow: 0 0 6px rgba(74, 222, 128, 0.40); }

/* LIVE — currently ticking, cyan + soft pulse. */

.bladeTime-live {
  border-color: rgba(77, 217, 255, 0.55);
  background: rgba(15, 40, 60, 0.65);
  box-shadow: inset 0 0 10px rgba(77, 217, 255, 0.10);
  animation: bladeTimeLivePulse 2.2s ease-in-out infinite;
}

.bladeTime-live span { color: rgba(180, 230, 255, 0.95); }

.bladeTime-live strong { color: #d6f5ff; text-shadow: 0 0 6px rgba(77, 217, 255, 0.50); }

/* IDLE — not started, muted with em-dash. */

.bladeTime-idle {
  border-color: rgba(77, 217, 255, 0.10);
  background: rgba(8, 14, 22, 0.45);
}

.bladeTime-idle span { color: rgba(140, 170, 190, 0.40); }

.bladeTime-idle strong { color: rgba(180, 210, 225, 0.45); }

/* TURBINE TOTAL — amber accent so it matches the hero accent. */

.bladeTime-total {
  border-color: rgba(255, 178, 115, 0.42);
  background: rgba(40, 25, 12, 0.55);
}

.bladeTime-total span { color: rgba(255, 200, 150, 0.85); }

.bladeTime-total strong { color: #ffd9a8; text-shadow: 0 0 6px rgba(255, 178, 115, 0.45); }

@keyframes bladeTimeLivePulse {
  0%, 100% { box-shadow: inset 0 0 10px rgba(77, 217, 255, 0.10); }
  50%      { box-shadow: inset 0 0 14px rgba(77, 217, 255, 0.22); }
}

/* Iteration 27 — site-wide subtle holographic cyan halo.
   Low-opacity outer + inset glow layered onto frame/panel/spec elements.
   Explicitly excludes .bladeChip (lines 205–276) which owns its own
   amber/cyan halo system. */

.hudFrame,
.panelHead,
.sysId,
.turbineSpecCell,
.specRow,
.platformRow {
  box-shadow:
    0 0 18px rgba(77, 217, 255, 0.029),
    inset 0 0 22px rgba(77, 217, 255, 0.020);
}

/* === DRONE MARKER (wireframe stage) ======================================
   Travels along the blade as the pass progresses. Vertical position is
   computed in JS and applied via the inline `top` style; edge passes
   hover well off the blade silhouette, face passes hover just to one
   side so the blade is never overlaid. */

.droneMarker {
  position: absolute;
  transform: translate(-50%, -50%);
  /* Always green — the drone is a constant signal across all passes. */
  color: #4ade80;
  pointer-events: none;
  z-index: 3;
  filter:
    drop-shadow(0 0 6px rgba(74, 222, 128, 0.70))
    drop-shadow(0 0 14px rgba(74, 222, 128, 0.35));
  animation: droneHover 2.6s ease-in-out infinite;
}

.droneSide-center      { left: 50%; }

.droneSide-right       { left: 74%; }

.droneSide-left        { left: 26%; }

.droneSide-faceRight   { left: 67%; }

.droneSide-faceLeft    { left: 33%; }

.droneSvg { display: block; }

/* Spinning rotor blur — give each ellipse a slight per-corner offset by
   transforming around its own cx/cy. CSS animation rotates the whole
   element around its computed center via transform-origin. */

.droneRotor {
  transform-box: fill-box;
  transform-origin: center;
  animation: droneRotorSpin 0.18s linear infinite;
}

@keyframes droneRotorSpin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Gentle vertical bob so the drone reads as hovering, not pinned. */

@keyframes droneHover {
  0%, 100% { margin-top: 0; }
  50%      { margin-top: -4px; }
}

/* Scan beam shooting from the drone toward the blade. For edge passes
   the beam points inward toward the centerline; for face passes it
   drops straight down onto the blade face. */

.droneScanBeam {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 70px;
  height: 2px;
  background: linear-gradient(
    90deg,
    rgba(74, 222, 128, 0.9) 0%,
    rgba(74, 222, 128, 0.25) 70%,
    transparent 100%
  );
  transform-origin: 0 50%;
  opacity: 0.85;
  filter: drop-shadow(0 0 4px #4ade80);
  animation: droneScanPulse 1.4s ease-in-out infinite;
}

.droneSide-right     .droneScanBeam { transform: translate(0, -50%) rotate(180deg); }

.droneSide-left      .droneScanBeam { transform: translate(0, -50%) rotate(0deg); }

.droneSide-faceRight .droneScanBeam { transform: translate(0, -50%) rotate(180deg); }

.droneSide-faceLeft  .droneScanBeam { transform: translate(0, -50%) rotate(0deg); }

.droneSide-center    .droneScanBeam {
  transform: translate(-50%, 0) rotate(90deg);
  transform-origin: 50% 0;
}

@keyframes droneScanPulse {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 0.95; }
}

/* Solid LIDAR link line between drone and blade for PS/SS passes only.
   The line is fully opaque end-to-end (no gradient fade) so it reads as a
   continuous laser link. A short bright "ping" travels from the drone to
   the blade and back, mimicking a LIDAR pulse out + return. */

.droneLinkLine {
  position: absolute;
  left: 50%;
  top: 50%;
  height: 1px;
  /* 35px shorter than the original so the line stops cleanly at the
     blade edge instead of overshooting past it. */
  width: calc(17vw - 35px);
  max-width: 185px;
  pointer-events: none;
  background: #4ade80;
  filter: drop-shadow(0 0 3px rgba(74, 222, 128, 0.65))
          drop-shadow(0 0 8px rgba(74, 222, 128, 0.30));
  overflow: hidden;
  /* Gentle breathing pulse on the base line itself — the "lighter signal"
     that travels out and comes back, on top of the bright ping segment. */
  animation: droneLinkBreath 1.8s ease-in-out infinite;
}

@keyframes droneLinkBreath {
  0%, 100% {
    opacity: 0.55;
    filter: drop-shadow(0 0 2px rgba(74, 222, 128, 0.45))
            drop-shadow(0 0 6px rgba(74, 222, 128, 0.18));
  }
  50% {
    opacity: 1;
    filter: drop-shadow(0 0 4px rgba(74, 222, 128, 0.85))
            drop-shadow(0 0 12px rgba(74, 222, 128, 0.45));
  }
}

/* PS pass — drone is on the right (left:67%), line extends LEFT toward
   the blade. transform-origin puts the drone end at the origin so the
   ping animation's direction is intuitive (0% = drone, 100% = blade). */

.droneSide-faceRight .droneLinkLine {
  transform: translate(-100%, -50%);
}

.droneSide-faceRight .droneLinkPing {
  /* Right→left ping: starts at the drone (right edge → 100%) and travels
     to the blade (left edge → 0%), then snaps back for the return ping.
     Note: in PS the .droneLinkLine has been translated -100%, so its
     LEFT edge points to the blade and its RIGHT edge points to the drone.
     We animate left from 100% (drone) down to 0% (blade). */
  animation: droneLidarPingRight 1.8s ease-in-out infinite;
}

/* SS pass — drone is on the left (left:33%), line extends RIGHT. */

.droneSide-faceLeft .droneLinkLine {
  transform: translate(0, -50%);
}

.droneSide-faceLeft .droneLinkPing {
  /* Left→right ping: starts at the drone (left edge → 0%) and travels to
     the blade (right edge → 100% minus ping width). */
  animation: droneLidarPingLeft 1.8s ease-in-out infinite;
}

/* The travelling pulse — a short, bright segment that slides along the
   line. Brighter than the base line and with a stronger glow so it reads
   as an active LIDAR return on top of the steady connection. */

.droneLinkPing {
  position: absolute;
  top: -1px;
  height: 3px;
  width: 18%;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(180, 255, 200, 0.95) 50%,
    transparent 100%
  );
  border-radius: 2px;
  filter: drop-shadow(0 0 4px #4ade80)
          drop-shadow(0 0 10px rgba(74, 222, 128, 0.70));
  will-change: left;
}

/* Right-side drone: 0% drone → 50% reaches blade → 100% back at drone. */

@keyframes droneLidarPingRight {
  0%   { left: 100%; opacity: 0.0; }
  8%   { opacity: 1; }
  48%  { left: 0%;   opacity: 1; }
  52%  { left: 0%;   opacity: 1; }
  92%  { opacity: 1; }
  100% { left: 100%; opacity: 0.0; }
}

/* Left-side drone: 0% drone → 50% reaches blade → 100% back at drone. */

@keyframes droneLidarPingLeft {
  0%   { left: 0%;   opacity: 0.0; }
  8%   { opacity: 1; }
  48%  { left: 82%;  opacity: 1; }
  52%  { left: 82%;  opacity: 1; }
  92%  { opacity: 1; }
  100% { left: 0%;   opacity: 0.0; }
}
