/* The portal — Evren's universe, two views deep (js/map.js).
   View one: the Void above, six spiral galaxies below in two rows of three.
   View two: the dive into a galaxy's cone of planets, with a vertical
   minimap riding on the left. The portal button itself (#map-btn, .map-orb)
   stays in base.css. */

#map {
  position: fixed; inset: 0; z-index: 30;
  background:
    radial-gradient(120% 80% at 50% 0%, #171233 0%, transparent 60%),
    linear-gradient(#0A0820, #060512);
  overflow: hidden;
  opacity: 0;
  transition: opacity 0.35s ease;
  cursor: pointer;
}
#map.show { opacity: 1; }
/* A picker is a place, not a popup: no dark to tap your way out of. */
#map.picker { cursor: auto; }

/* The starfield behind every view: painted once, never blinks on a swap. */
.map-sky {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
}
.map-view {
  position: absolute;
  inset: 0;
}

/* ---------- view one: the universe ---------- */

.universe {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.2em;
  width: 100%;
  height: 100%;
  padding: 4vh 5vw;
  overflow-y: auto;
}

/* The portal tutorial: the Void is the only door that answers. The galaxies
   are still there, still turning, just not yet the learner's business. */
.universe.focus-void .galaxy-card {
  opacity: 0.2;
  filter: blur(2px) saturate(0.5);
  pointer-events: none;
  cursor: default;
}
.universe.focus-void .void-gate {
  animation: void-beckon 2s ease-in-out infinite;
}
@keyframes void-beckon {
  50% { transform: scale(1.06); filter: drop-shadow(0 0 26px rgba(154, 147, 184, 0.6)); }
}
@media (prefers-reduced-motion: reduce) {
  .universe.focus-void .void-gate { animation: none; filter: drop-shadow(0 0 26px rgba(154, 147, 184, 0.6)); }
}

/* The Void: a black mouth with rings, no edges, no box. Hover leans in. */
.void-gate {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5em;
  background: none;
  border: none;
  cursor: pointer;
  transition: transform 0.35s ease;
  flex-shrink: 0;
}
.void-gate:hover { transform: scale(1.09); }
.void-hole {
  position: relative;
  width: 74px; height: 44px;
  pointer-events: none;
}
.void-hole::before {
  content: '';
  position: absolute;
  left: 50%; top: 50%;
  width: 58px; height: 30px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 50%, #000 40%, #0B0A1F 68%, rgba(42, 27, 74, 0.8) 88%, transparent 100%);
  box-shadow: 0 0 22px rgba(74, 60, 140, 0.5), inset 0 0 10px #000;
}
.void-ring {
  position: absolute;
  left: 50%; top: 50%;
  border: 1px solid rgba(154, 147, 184, 0.35);
  border-radius: 50%;
  transform: translate(-50%, -50%) rotate(-10deg);
}
.void-ring.r1 { width: 78px; height: 34px; animation: void-sway 8s ease-in-out infinite alternate; }
.void-ring.r2 { width: 100px; height: 44px; border-color: rgba(154, 147, 184, 0.22); animation: void-sway 11s ease-in-out infinite alternate-reverse; }
.void-ring.r3 { width: 122px; height: 54px; border-color: rgba(154, 147, 184, 0.12); animation: void-sway 14s ease-in-out infinite alternate; }
@keyframes void-sway {
  from { transform: translate(-50%, -50%) rotate(-6deg); }
  to   { transform: translate(-50%, -50%) rotate(-16deg); }
}
.void-labels { display: flex; flex-direction: column; align-items: center; gap: 0.15em; }
.void-cap {
  font-family: var(--sans);
  font-size: 0.62rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: #B9B4E8;
}
.void-name {
  font-family: var(--serif);
  font-size: 1.05rem;
  color: var(--cream);
}

.map-locked-note {
  font-family: var(--sans);
  font-style: italic;
  font-size: 0.78rem;
  color: var(--lavender);
  opacity: 0.85;
}

/* The six galaxies: three columns, two rows, breathing room between. */
.universe-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1vh 3vw;
  width: min(1150px, 94vw);
}
.galaxy-card {
  --gal: #E8C16A;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  background: none;
  border: none;
  padding: 0.4em 0.9em 0.9em;
  cursor: pointer;
  opacity: 0;
  animation: menu-word-in 0.6s ease forwards;
  transition: transform 0.35s ease;
}
.galaxy-card:hover { transform: scale(1.06); }
/* The galaxy itself: a flat-drawn spiral, tilted into an ellipse, spinning
   slowly in its tilted plane. The nebula glow breathes underneath. */
.galaxy-tilt {
  display: block;
  align-self: center;
  perspective: 700px;
  filter: drop-shadow(0 0 26px color-mix(in srgb, var(--gal) 22%, transparent));
}
.galaxy-spin {
  display: block;
  transform: rotateX(60deg);
}
.galaxy-canvas {
  display: block;
  width: clamp(150px, 17vw, 240px);
  height: clamp(150px, 17vw, 240px);
  animation: galaxy-turn 90s linear infinite;
}
.galaxy-card:hover .galaxy-canvas { animation-duration: 34s; }
@keyframes galaxy-turn { to { transform: rotate(360deg); } }

.galaxy-label {
  display: flex;
  align-items: center;
  gap: 0.55em;
  font-family: var(--sans);
  font-size: 0.86rem;
  color: var(--cream);
  margin-top: -0.5em;
}
.galaxy-dash {
  width: 14px; height: 2px;
  border-radius: 2px;
  background: var(--gal);
  box-shadow: 0 0 7px color-mix(in srgb, var(--gal) 70%, transparent);
}
.galaxy-tagline {
  font-family: var(--sans);
  font-size: 0.68rem;
  color: var(--lavender);
  opacity: 0.8;
  margin: 0.15em 0 0 1.6em;
}
.galaxy-soon {
  font-family: var(--sans);
  font-style: italic;
  font-size: 0.66rem;
  color: var(--lavender);
  opacity: 0.7;
  margin: 0.1em 0 0 1.6em;
}

/* Locked: the cone can be looked at, but its doors will not open yet. */
.cone-locked {
  position: absolute;
  left: 50%;
  top: max(3vh, 16px);
  transform: translateX(-50%);
  z-index: 4000;
  font-family: var(--sans);
  font-style: italic;
  font-size: 0.76rem;
  color: var(--lavender);
  opacity: 0.85;
  pointer-events: none;
  text-align: center;
}

/* A letter or a word that escapes a hovered galaxy, planet or moon. White,
   so it reads against every planet colour and every nebula behind it. */
.fly-glyph {
  position: absolute;
  font-family: var(--serif);
  font-size: 1.1rem;
  color: #fff;
  text-shadow:
    0 0 10px rgba(255, 255, 255, 0.95),
    0 0 24px rgba(190, 215, 255, 0.55),
    0 2px 6px rgba(0, 0, 0, 0.75);
  pointer-events: none;
  animation: glyph-fly 1.5s ease-out forwards;
  white-space: nowrap;
  z-index: 6;
}
@keyframes glyph-fly {
  0%   { opacity: 0; transform: translate(0, 0) scale(0.7); }
  15%  { opacity: 1; }
  100% { opacity: 0; transform: translate(var(--gx, 40px), var(--gy, -70px)) scale(1.15); }
}

/* ---------- the maker's note (a galaxy still being built) ---------- */

.map-building {
  position: relative;
  max-width: 34em;
  padding: 2em 2.4em;
  border: 1px solid rgba(154, 147, 184, 0.3);
  border-radius: 18px;
  background: rgba(16, 14, 40, 0.92);
  cursor: auto;
  text-align: left;
}
.building-back {
  position: absolute;
  top: 0.9em; left: 1em;
  background: none;
  border: 1px solid rgba(154, 147, 184, 0.35);
  border-radius: 50%;
  width: 2em; height: 2em;
  color: var(--lavender);
  cursor: pointer;
  transition: border-color 0.25s ease, color 0.25s ease;
}
.building-back:hover { border-color: var(--cream); color: var(--cream); }
.building-head {
  font-family: var(--serif);
  font-size: 1.15rem;
  color: var(--cream);
  margin: 0.2em 0 0.8em 2em;
}
.building-line {
  font-family: var(--sans);
  font-size: 0.85rem;
  line-height: 1.65;
  color: var(--lavender);
  margin-bottom: 0.8em;
}
.building-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6em;
  margin-top: 1.1em;
}
.building-btn {
  font-family: var(--sans);
  font-size: 0.8rem;
  padding: 0.45em 1.1em;
  color: var(--lavender);
  background: none;
  border: 1px solid rgba(154, 147, 184, 0.4);
  border-radius: 999px;
  cursor: pointer;
  text-decoration: none;
  transition: border-color 0.25s ease, background 0.25s ease;
}
.building-btn:hover { border-color: var(--gold); background: rgba(232, 193, 106, 0.08); }
.building-btn.go { border-color: rgba(79, 182, 166, 0.6); color: #4FB6A6; }
.building-btn.go:hover { border-color: #4FB6A6; background: rgba(79, 182, 166, 0.1); }
.building-btn.donate { border-color: rgba(232, 193, 106, 0.5); color: var(--gold); }
.building-note {
  font-family: var(--sans);
  font-style: italic;
  font-size: 0.7rem;
  color: var(--lavender);
  opacity: 0.7;
  margin-top: 0.6em;
}

/* ---------- view two: the dive ---------- */

.cone {
  position: absolute;
  inset: 0;
  cursor: auto;
  animation: cone-in 0.6s ease;
  overflow: hidden;
}
@keyframes cone-in {
  from { opacity: 0; transform: scale(1.25); }
  to   { opacity: 1; transform: none; }
}
/* The edge of the galaxy: the last planet pulls back against the scroll,
   twice, before it lets go. Declared before .leave so that leaving always
   wins when both are on. */
.cone.at-edge { animation: cone-edge 0.5s ease; }
@keyframes cone-edge {
  40% { transform: translateY(-16px); }
}
.cone.at-edge .cone-hint { animation: hint-wake 1s ease; }
@keyframes hint-wake {
  40% { color: var(--cream); opacity: 1; letter-spacing: 0.14em; }
}

.cone.leave { animation: cone-out 0.45s ease forwards; }
@keyframes cone-out {
  to { opacity: 0; transform: scale(1.3); }
}

/* A planet in the cone: the loop owns its transform (position, scale, blur). */
.cone-planet {
  position: absolute;
  left: 0; top: 0;
  /* Only the two the compositor handles for free. Promising `filter` too
     would pin a layer per planet for something now written rarely. */
  will-change: transform, opacity;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* No transition on transform, opacity or filter: the travel loop writes
     all three every frame, and a transition would restart itself on every
     write, fighting the loop instead of easing it. */
}
/* The ball sits above a moon on the far side of its orbit and below one on
   the near side; the loop moves the moons between those layers. */
.cone-ball {
  --pc: #E8C16A;
  position: relative;
  z-index: 2;
  width: 150px; height: 150px;
  border-radius: 50%;
  background:
    radial-gradient(circle at 30% 26%, rgba(255, 255, 255, 0.95) 0%, transparent 26%),
    radial-gradient(circle at 33% 30%, #fff 2%, var(--pc) 50%, color-mix(in srgb, var(--pc) 34%, #0A0820) 100%);
  box-shadow:
    0 0 42px color-mix(in srgb, var(--pc) 28%, transparent),
    inset -18px -22px 44px rgba(6, 5, 18, 0.72),
    inset 6px 8px 26px rgba(255, 255, 255, 0.09);
  pointer-events: auto;
  transition: box-shadow 0.3s ease;
}
/* A twin planet: two smaller balls share one stop and circle the empty
   middle of the pair. The frame gives the node its size (so the name sits
   below and the hover area is whole); the balls orbit inside it, placed by
   the rAF loop. */
.cone-twin {
  position: relative;
  width: 150px; height: 150px;
}
.cone-ball.twin-ball {
  position: absolute;
  left: 50%; top: 50%;
  width: 94px; height: 94px;
}

/* Hovered: the planet warms and leans out (the scale rides the loop). */
.cone-planet.hot .cone-ball {
  box-shadow:
    0 0 68px color-mix(in srgb, var(--pc) 55%, transparent),
    inset -18px -22px 44px rgba(6, 5, 18, 0.66),
    inset 6px 8px 26px rgba(255, 255, 255, 0.14);
}
.cone-planet.hot .cone-name { color: #fff; }
.cone-name {
  margin-top: 0.5em;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 1.05rem;
  color: rgba(243, 234, 216, 0.88);
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.85);
  white-space: nowrap;
  pointer-events: none;
  transition: color 0.25s ease;
}
.cone-planet.real .cone-name { color: var(--cream); }
/* A unit not built yet shakes its head. */
.cone-planet.nope .cone-ball { animation: shake 0.4s ease; }

/* The landing: the chosen planet rushes up to meet the traveller. */
.cone.landing .cone-planet:not(.touchdown) { opacity: 0 !important; transition: opacity 0.4s ease; }
.cone-planet.touchdown {
  animation: touchdown 0.55s cubic-bezier(0.5, 0, 0.9, 0.6) forwards;
  z-index: 5000 !important;
  filter: none !important;
  pointer-events: none;
}
@keyframes touchdown {
  to { transform: translate(50vw, 46vh) translate(-50%, -50%) scale(9); opacity: 0; }
}

/* Moons ride the rAF loop; each is a small pale sphere with its own shading. */
.cone-moon {
  position: absolute;
  left: 50%; top: 40%;
  width: 30px; height: 30px;
  border-radius: 50%;
  background: radial-gradient(circle at 33% 28%, #fff, #C9C6DE 52%, #4A4766 100%);
  box-shadow: inset -5px -6px 12px rgba(6, 5, 18, 0.6), 0 0 12px rgba(201, 198, 222, 0.35);
  pointer-events: none;
  /* The orbit writes opacity per frame; a transition here would fight it. */
}
.cone-moon.door { pointer-events: auto; cursor: pointer; }
.cone-moon.door:hover { box-shadow: inset -5px -6px 12px rgba(6, 5, 18, 0.5), 0 0 20px rgba(243, 234, 216, 0.9); }

/* Out of reach: too far down the chain, or swollen past the frame on its way
   in. The whole planet stops answering, children included. This has to name
   the descendants: a child that sets pointer-events: auto stays a hit target
   even when its parent is set to none, so the ball and the moons would go on
   collecting clicks from inside the cluster. */
.cone-planet.off,
.cone-planet.off .cone-ball,
.cone-planet.off .cone-moon { pointer-events: none; }
.cone-planet.off { cursor: default; }

/* A moon says its own name: a quiet plate under the planet, in the
   universe's colours. Centred by margin, never by transform, so the fade
   cannot wipe its position. */
.cone-moon-label {
  position: absolute;
  left: 0; right: 0;
  top: calc(100% + 0.35em);
  margin: 0 auto;
  width: max-content;
  max-width: 14em;
  padding: 0.3em 0.9em;
  border: 1px solid rgba(185, 180, 232, 0.5);
  border-radius: 999px;
  background: rgba(16, 14, 40, 0.85);
  box-shadow: 0 0 18px rgba(116, 112, 200, 0.25);
  font-family: var(--serif);
  font-size: 0.92rem;
  color: #B9B4E8;
  text-shadow: 0 0 10px rgba(150, 148, 220, 0.5);
  white-space: nowrap;
  text-align: center;
  opacity: 0;
  transition: opacity 0.25s ease;
  pointer-events: none;
  z-index: 5;
}
.cone-moon-label.show { opacity: 1; }

/* The map: a vertical zigzag of the galaxy's planets, riding the left edge.
   The first planet sits at the top; the marker walks down as you travel. */
.cone-mini {
  position: absolute;
  left: max(2vw, 14px);
  top: 50%;
  transform: translateY(-50%);
  z-index: 4000;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5em;
  max-height: 76vh; /* clear of the portal orb above and the controls below */
  overflow: hidden;
  padding: 0.9em 0.8em;
  border: 1px solid rgba(154, 147, 184, 0.3);
  border-radius: 14px;
  background: rgba(13, 11, 34, 0.82);
  cursor: auto;
}
.cone-mini-title {
  font-family: var(--sans);
  font-size: 0.62rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: #B9B4E8;
}
.cone-mini canvas { display: block; }
.cone-mini-cap {
  font-family: var(--sans);
  font-size: 0.68rem;
  color: var(--lavender);
  max-width: 11em;
  text-align: center;
}

/* One line on a wide screen; on a phone it folds instead of running off both
   edges. The width is the whole rule: it holds the sentence together until
   the screen is too narrow for it, then lets it break. */
.cone-hint {
  position: absolute;
  left: 50%;
  bottom: max(3vh, 18px);
  transform: translateX(-50%);
  z-index: 4000;
  width: max-content;
  max-width: min(44em, 82vw);
  font-family: var(--sans);
  font-size: 0.74rem;
  line-height: 1.6;
  letter-spacing: 0.08em;
  color: var(--lavender);
  opacity: 0.8;
  text-align: center;
  pointer-events: none;
}

/* A picker's instruction: Evren's ask, held across the top of the galaxy.
   Centred by margin, never by transform — the entrance animation owns the
   transform, and a translate here would be wiped the moment it ran. The
   width leaves both corners free, so it never crowds the portal orb or the
   Lexiverse. */
.cone-instruction {
  position: absolute;
  left: 0; right: 0;
  top: max(4vh, 22px);
  margin: 0 auto;
  z-index: 4000;
  width: min(34em, 62vw);
  font-family: var(--serif);
  font-size: clamp(1rem, 2.4vw, 1.25rem);
  line-height: 1.55;
  color: var(--cream);
  text-align: center;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.8);
  pointer-events: none;
  opacity: 0;
  animation: instruction-in 0.8s ease 0.3s forwards;
}
@keyframes instruction-in {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: none; }
}

/* The arrow that pulls the map out. It exists only on a phone, where the map
   itself is parked off the left edge to leave the galaxy the whole screen. */
.cone-mini-pull { display: none; }

/* Phones: two galaxy columns, and the map hides to the left until it is
   asked for. The arrow stays on the edge; the zigzag slides out beside it. */
@media (max-width: 720px) {
  .universe-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cone-mini {
    left: 30px;
    transform: translate(calc(-100% - 34px), -50%) scale(0.8);
    transform-origin: left center;
    transition: transform 0.35s ease;
  }
  .cone-mini.open { transform: translateY(-50%) scale(0.8); }

  .cone-mini-pull {
    display: block;
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    z-index: 4001;
    width: 24px;
    height: 54px;
    padding: 0;
    border: 1px solid rgba(154, 147, 184, 0.3);
    border-left: none;
    border-radius: 0 12px 12px 0;
    background: rgba(13, 11, 34, 0.82);
    color: #B9B4E8;
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
  }
}

@media (prefers-reduced-motion: reduce) {
  .galaxy-canvas { animation: none; }
  .void-ring { animation: none; }
  .cone { animation: none; }
  .cone.at-edge { animation: none; }
  /* Depth still reads through size and dimness, at no cost at all. */
  .cone-planet { filter: none !important; }
}
