/* ============================================================
   Sail Race Tracker — "Explore the system" WebGL scene
   (pairs with js/hero3d.js — lives on product.html as a standalone
   .hero3d-section; legacy .hero--3d hero-overlay rules kept so the
   module still works if the stage is ever hosted inside a hero).
   Load AFTER css/styles.css. Owns only .hero3d-* / .hero-hub-*.
   ============================================================ */

.hero--3d{position:relative;overflow:hidden}

/* Hero copy sits above the canvas; let drags pass through except on controls */
.hero--3d .hero-grid{position:relative;z-index:1;pointer-events:none}
.hero--3d .hero-grid a,
.hero--3d .hero-grid button,
.hero--3d .hero-grid .btn,
.hero--3d .hero-grid img{pointer-events:auto}

/* Full-bleed stage behind the hero copy */
.hero3d-stage{position:absolute;inset:0;z-index:0}

/* Legibility scrim: sits ABOVE the canvas but BELOW the hero copy (the copy grid
   is z-index:1 in a separate header-level stacking context). Left-weighted so the
   text column stays crisp while the scene reads through on the right. */
.hero3d-stage::after{
  content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  background:linear-gradient(102deg,
    rgba(238,243,249,.97) 0%,
    rgba(238,243,249,.88) 22%,
    rgba(238,243,249,.55) 40%,
    rgba(238,243,249,.12) 55%,
    rgba(238,243,249,0)   66%);
}
@media (prefers-color-scheme:dark){
  .hero3d-stage::after{
    background:linear-gradient(102deg,
      rgba(12,22,34,.96) 0%,
      rgba(12,22,34,.84) 22%,
      rgba(12,22,34,.5)  40%,
      rgba(12,22,34,.12) 55%,
      rgba(12,22,34,0)   66%);
  }
}
/* On stacked/narrow layouts the copy is full-width, so scrim from the bottom up */
@media (max-width:760px){
  .hero3d-stage::after{
    background:linear-gradient(180deg,
      rgba(238,243,249,.35) 0%,
      rgba(238,243,249,.82) 42%,
      rgba(238,243,249,.96) 100%);
  }
}
@media (max-width:760px) and (prefers-color-scheme:dark){
  .hero3d-stage::after{
    background:linear-gradient(180deg,
      rgba(12,22,34,.35) 0%,
      rgba(12,22,34,.82) 42%,
      rgba(12,22,34,.96) 100%);
  }
}
/* Belt-and-braces: a hair of shadow keeps the lead readable where the scrim thins */
.hero--3d .hero-copy .lead{text-shadow:0 1px 10px var(--bg)}

.hero3d-stage canvas{
  display:block;width:100%;height:100%;
  touch-action:pan-y;              /* vertical page scroll always works */
  -webkit-user-select:none;user-select:none;
  -webkit-tap-highlight-color:transparent;
  cursor:grab;
  -webkit-mask-image:linear-gradient(to bottom,#000 78%,transparent 100%);
          mask-image:linear-gradient(to bottom,#000 78%,transparent 100%);
}
.hero3d-stage canvas:active{cursor:grabbing}

/* Fallback illustration: visible by default; hero3d.js adds .is-live to the
   stage only after WebGL init + the first frame render succeed, which fades
   the image out. On failure the stage gets .is-fallback and the image stays. */
.hero3d-stage .hero3d-fallback,
.hero3d-stage.is-fallback img{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;display:block;opacity:.28;
  -webkit-mask-image:linear-gradient(to bottom,#000 70%,transparent 100%);
          mask-image:linear-gradient(to bottom,#000 70%,transparent 100%);
}
/* Hard-failure state: the illustration IS the hero now, so give it real presence
   (the ::after scrim above it keeps the copy readable). */
.hero3d-stage.is-fallback img{opacity:.55}
.hero3d-stage .hero3d-fallback{transition:opacity .5s ease}
.hero3d-stage.is-live .hero3d-fallback{
  opacity:0;visibility:hidden;
  transition:opacity .5s ease,visibility 0s .5s;
}

@media (prefers-reduced-motion:reduce){
  .hero3d-stage .hero3d-fallback{transition:none}
  .hero3d-stage canvas{cursor:default}
}

/* ============================================================
   Navigation hub — chips, hover label, focus card.
   All of this DOM is injected by js/hero3d.js (index.html unchanged).
   Tokens only: light/dark come for free via styles.css custom props.
   ============================================================ */

/* Three real <button> chips under the hero CTAs (inside .hero-copy).
   Pointer events re-enabled by the .hero-grid button rule above. */
.hero-hub-chips{display:flex;flex-wrap:wrap;gap:10px;margin-top:26px}
.hero-hub-chip{
  display:inline-flex;align-items:center;gap:9px;
  min-height:42px;padding:9px 18px;
  border-radius:var(--radius-pill);
  border:1px solid var(--glass-border);
  background:var(--glass-bg);
  -webkit-backdrop-filter:saturate(1.4) blur(10px);
          backdrop-filter:saturate(1.4) blur(10px);
  color:var(--ink);
  font-family:'Space Grotesk',sans-serif;font-weight:600;font-size:.9rem;
  cursor:pointer;box-shadow:var(--elev-1);
  transition:border-color .2s ease,color .2s ease,background .2s ease,
             transform .2s ease,box-shadow .2s ease;
}
.hero-hub-chip .dot{
  width:8px;height:8px;border-radius:50%;flex:none;
  background:var(--accent);box-shadow:0 0 8px var(--accent);
}
.hero-hub-chip:hover{
  border-color:var(--accent);color:var(--accent);
  transform:translateY(-2px);box-shadow:var(--elev-2);
}
.hero-hub-chip.is-active{
  border-color:var(--accent);color:var(--accent);background:var(--accent-soft);
}

/* Floating hover label — projected next to the 3D target each frame */
.hero-hub-label{
  position:absolute;left:0;top:0;z-index:3;pointer-events:none;
  white-space:nowrap;padding:6px 12px;
  border-radius:var(--radius-pill);
  font-family:'Space Grotesk',sans-serif;font-weight:600;font-size:.8rem;
  color:var(--ink);
  background:var(--glass-bg-strong);border:1px solid var(--glass-border);
  -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
  box-shadow:var(--elev-2);will-change:transform;
}
.hero-hub-label[hidden]{display:none}

/* Glass info card: right rail on desktop, bottom sheet on small screens */
.hero-hub-card{
  position:absolute;z-index:3;top:50%;right:clamp(16px,6vw,84px);
  width:min(340px,calc(100vw - 32px));
  padding:22px 22px 20px;
  border-radius:var(--radius-lg);
  background:var(--glass-bg-strong);border:1px solid var(--glass-border);
  -webkit-backdrop-filter:saturate(1.4) blur(14px);
          backdrop-filter:saturate(1.4) blur(14px);
  box-shadow:var(--elev-3);
  opacity:0;transform:translateY(-50%) translateX(14px);
  transition:opacity .35s ease,transform .35s ease;
}
.hero-hub-card.is-open{opacity:1;transform:translateY(-50%) translateX(0)}
.hero-hub-card[hidden]{display:none}
.hero-hub-card:focus{outline:none}
.hero-hub-card:focus-visible{outline:2px solid var(--ring);outline-offset:2px}
.hero-hub-card__title{
  font-family:'Space Grotesk',sans-serif;font-size:1.15rem;
  margin:0 0 10px;color:var(--ink);
}
.hero-hub-card__line{margin:0 0 8px;font-size:.92rem;line-height:1.55;color:var(--muted)}
.hero-hub-card__actions{display:flex;gap:10px;margin-top:14px;flex-wrap:wrap}
.hero-hub-card__actions .btn{min-height:40px}

/* Screen-reader-only live region for hub announcements */
.hero-hub-live{
  position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;
}

@media (max-width:700px){
  .hero-hub-chip{min-height:44px}
  .hero-hub-card{
    top:auto;right:12px;left:12px;bottom:12px;width:auto;
    max-height:min(55vh,340px);overflow:auto;
    transform:translateY(14px);
  }
  .hero-hub-card.is-open{transform:translateY(0)}
  .hero-hub-card__actions .btn{min-height:44px;flex:1 1 auto;justify-content:center}
}

@media (prefers-reduced-motion:reduce){
  .hero-hub-chip,.hero-hub-card{transition:none}
  .hero-hub-chip:hover{transform:none}
  .hero-hub-card{opacity:1;transform:translateY(-50%)}
}
@media (prefers-reduced-motion:reduce) and (max-width:700px){
  .hero-hub-card{transform:none}
}

/* ============================================================
   Standalone section variant — product.html "Explore the system".
   #hero3d sits inside .hero3d-section (a normal page section, not a
   hero header): the stage is a real block with its own height, the
   heading + injected chips live in .hero3d-head above it, and the
   scrim becomes soft top/bottom fades into the page background so
   the scene blends with no hard horizontal edge (light + dark come
   free via var(--bg)). These rules are appended LAST on purpose —
   they out-cascade the equal-specificity hero rules above.
   ============================================================ */
.hero3d-section{position:relative;overflow:hidden}
.hero3d-head{position:relative;z-index:1;margin-bottom:26px}
.hero3d-head .hero-hub-chips{margin-top:18px}

.hero3d-stage--section{
  position:relative;inset:auto;z-index:0;
  height:clamp(440px,64vh,660px);
}
.hero3d-stage--section canvas{
  -webkit-mask-image:none;mask-image:none;
}
/* soft blend into the page above and below instead of the copy scrim */
.hero3d-stage--section::after{
  background:linear-gradient(180deg,
    var(--bg) 0%,transparent 13%,
    transparent 87%,var(--bg) 100%);
}
/* the fallback illustration IS the content here — give it presence */
.hero3d-stage--section .hero3d-fallback,
.hero3d-stage--section.is-fallback img{
  opacity:.5;
  -webkit-mask-image:none;mask-image:none;
}
.hero3d-stage--section.is-fallback img{opacity:.85}

@media (max-width:760px){
  .hero3d-stage--section{height:clamp(380px,58vh,520px)}
}

