/* ─────────────────────────────────────────────────────────────
   OCTOLUS 3D — deltas only.
   octolus.css carries the palette, the type scale, the venture
   sections and the label styling. Everything here exists because the
   hero is a WebGL canvas instead of a 2D one; duplicating the rest
   would guarantee the two pages drift apart.
   ───────────────────────────────────────────────────────────── */

/* The renderer's canvas replaces #tank, and is TRANSPARENT: ambient.js paints
   the water, the shafts and the fauna on a fixed canvas behind it. */
#gl {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 1;
  touch-action: none;              /* a drag turns the creature, not the page */
  cursor: grab;
}
#gl.dragging { cursor: grabbing; }

/* The water layer, behind the transparent WebGL canvas. */
#ambient {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  display: block;
  pointer-events: none;
}

/* Labels sit above the canvas but must not eat drags aimed at the creature. */
.nodes { pointer-events: none; }
.node  { pointer-events: auto; }

/* An arm on the far side of the body: dimmed, not hidden — it is still a real
   arm and still clickable. */
.node.behind { opacity: .38; }

/* ── CHROME ────────────────────────────────────────────────── */
.chrome {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .8rem clamp(.9rem, 3vw, 2rem);
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  pointer-events: none;
  background: linear-gradient(to top,
    color-mix(in oklab, var(--abyss) 82%, transparent), transparent);
}
.chrome > * { pointer-events: auto; }

.back {
  color: var(--silt-500);
  text-decoration: none;
  transition: color .2s ease;
}
.back:hover { color: var(--silt-100); }

.tag {
  color: var(--silt-500);
  border: 1px solid var(--silt-700);
  border-radius: 999px;
  padding: .28rem .7rem;
}

.hint {
  position: absolute;
  left: 50%;
  bottom: 6.4rem;
  transform: translateX(-50%);
  z-index: 3;
  font-family: var(--mono);
  font-size: .64rem;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--silt-500);
  pointer-events: none;
  opacity: 0;
  animation: rise 1.2s ease 3.2s forwards;
}
.hint.gone { opacity: 0 !important; transition: opacity .4s ease; }

/* the scroll cue would collide with the hint; lift it clear of the chrome bar */
.cue { bottom: 2.6rem; }

.fallback {
  position: fixed;
  inset: auto 1rem 5rem 1rem;
  text-align: center;
  color: var(--silt-300);
  z-index: 6;
}
.fallback a { color: var(--pink); }

@media (max-width: 720px) {
  .hint { bottom: 6.8rem; }
  /* "drag to turn" is the only instruction that matters on a touch screen,
     and the full line wraps to two on a phone */
  .hint-more { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .hint { animation-duration: .01ms; animation-delay: .01ms; }
}

/* ── VENTURE CARDS ─────────────────────────────────────────────
   A plain pill works over a flat 2D drawing. Over a lit 3D
   creature it disappeared, so these carry their own light: the venture's own
   mark, a hue-tinted glass panel, and a coloured glow that ties the card to
   the arm it hangs from. */
.node-inner {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: .1rem .55rem;
  padding: .42rem .72rem .42rem .5rem;
  border-radius: .72rem;
  background:
    linear-gradient(135deg,
      color-mix(in oklab, var(--arm, var(--pink)) 26%, transparent) 0%,
      color-mix(in oklab, var(--abyss) 88%, transparent) 58%),
    color-mix(in oklab, var(--abyss) 72%, transparent);
  border: 1px solid color-mix(in oklab, var(--arm, var(--pink)) 46%, transparent);
  box-shadow:
    0 10px 30px -14px color-mix(in oklab, var(--arm, var(--pink)) 85%, transparent),
    inset 0 1px 0 color-mix(in oklab, white 10%, transparent);
  backdrop-filter: blur(10px) saturate(1.25);
  transition: border-color .25s ease, box-shadow .25s ease,
              transform .25s cubic-bezier(.2,.7,.3,1), background .25s ease;
}

.node-icon {
  grid-row: span 2;
  width: 26px; height: 26px;
  border-radius: .42rem;
  display: block;
  background: color-mix(in oklab, var(--abyss) 70%, transparent);
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--arm, var(--pink)) 30%, transparent);
}

.node-text { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }

.node:hover .node-inner,
.node:focus-visible .node-inner {
  transform: translateY(-3px);
  border-color: var(--arm, var(--pink));
  box-shadow:
    0 16px 38px -14px color-mix(in oklab, var(--arm, var(--pink)) 95%, transparent),
    0 0 0 1px color-mix(in oklab, var(--arm, var(--pink)) 55%, transparent),
    inset 0 1px 0 color-mix(in oklab, white 16%, transparent);
}

/* Threads: which card belongs to which arm, drawn rather than guessed. */
.threads {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  overflow: visible;
  pointer-events: none;
  z-index: -1;                 /* behind the cards, above the creature */
}
.threads g { transition: opacity .3s ease; }

@media (max-width: 720px) {
  .node-icon { width: 20px; height: 20px; }
  .node-inner { padding: .34rem .6rem .34rem .42rem; }
}

/* An absolutely-positioned box is shrink-to-fit, and its available width is
   whatever remains between `left` and the container's edge. A card placed near
   the right edge therefore COLLAPSED to ~70px and its nowrap text spilled out
   and was clipped by the stage — it looked like overflow, it was compression.
   max-content stops it; the clamp in placeLabels keeps it on screen. */
.node {
  width: max-content;
  max-width: min(88vw, 22rem);
}

/* Hover brings a card fully forward, including the ones dimmed for being on
   the far side of the body — Ry: several read too dark to pick out. Hovering
   is an explicit request to look at that one, so it overrides the depth dim. */
.node.behind { opacity: .52; }
.node:hover, .node:focus-within { z-index: 3; }

.node:hover .node-inner,
.node:focus-within .node-inner {
  background:
    linear-gradient(135deg,
      color-mix(in oklab, var(--arm, var(--pink)) 42%, transparent) 0%,
      color-mix(in oklab, var(--abyss) 82%, transparent) 62%),
    color-mix(in oklab, var(--abyss) 68%, transparent);
}
.node:hover .node-name, .node:focus-within .node-name { color: #fff; }
.node:hover .node-icon, .node:focus-within .node-icon {
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--arm, var(--pink)) 75%, transparent);
}

/* ── VENTURE COVER HOVER (3D page only) ────────────────────────
   Ry asked whether the cover image could highlight on hover without fighting
   the glow that is already there. It would, if it were a second glow — the
   frame already carries a coloured drop shadow AND a tint overlay that mutes
   the screenshot. So this does not ADD an effect, it PULLS THE VEIL BACK:
   the tint steps aside, the image comes up to full clarity and eases in, and
   the existing glow tightens rather than being joined by another one.
   Deliberately no cursor change - the cover is not a link, the Visit button is. */
.arm-media {
  transition: box-shadow .35s ease, border-color .35s ease, transform .35s ease;
}
.arm-media img {
  transition: transform .65s cubic-bezier(.25,.46,.45,.94), filter .35s ease;
}
.arm-media::after { transition: opacity .35s ease; }

.arm-media:hover,
.arm:focus-within .arm-media {
  transform: translateY(-3px);
  border-color: color-mix(in oklab, var(--arm) 62%, transparent);
  /* same shadow, tighter and stronger - not a second light source */
  box-shadow: 0 26px 58px -24px var(--arm),
              0 0 0 1px color-mix(in oklab, var(--arm) 30%, transparent);
}
.arm-media:hover img,
.arm:focus-within .arm-media img { transform: scale(1.035); filter: saturate(1.14) brightness(1.06); }
.arm-media:hover::after,
.arm:focus-within .arm-media::after { opacity: .5; }

@media (prefers-reduced-motion: reduce) {
  .arm-media, .arm-media img, .arm-media::after { transition: none; }
  .arm-media:hover img { transform: none; }
}
