/* Entropic Labs — the foyer.
   ==========================================================================
   The way in. Four rooms hang in a dark field around the wordmark; the field
   itself is drawn by foyer/foyer.js on a canvas underneath. This stylesheet
   owns the layout, the type and the rest states, and nothing else on the site
   loads it — the studio, the games page, the Observatory and Butterfly Trails
   keep their own styles untouched.

   The tokens at the top are the studio's, copied verbatim from studio.html so
   the foyer sits in the same building. What is new here is one idea: every
   room carries a --glow, and the mark, the halo, the focus ring and the
   transition on the way out all read from it. Teal for the Observatory, the
   studio's pink for the Studio, violet for the Game Room, Butterfly Trails'
   amber for the trail.

   One responsive page, no m/ twin — like the Observatory and Butterfly
   Trails, the layout is a composition rather than prose, and a hand-tuned
   second copy would only ever drift. Desktop hangs the rooms around the
   wordmark; a phone unrolls the same four rooms into a trail you scroll.
   ========================================================================== */

:root{
  /* --- the studio's tokens, unchanged --- */
  --ink: #07050F;
  --panel: #130E22;
  --panel-raised: #1C1433;
  --ash: #9C93B8;
  --paper: #F1EEFB;
  --signal: #FF3FA0;
  --trace: #2FE0C7;
  --violet: #7C4DFF;
  --ember: #FFC46B;
  --hairline: rgba(241,238,251,0.12);
  --hairline-strong: rgba(241,238,251,0.22);

  --font-display: "Arial Narrow", "Helvetica Neue Condensed", "Roboto Condensed", Arial, sans-serif;
  --font-body: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;

  /* --- the foyer only --- */
  --void: #05040D;
  --sill-h: 3rem;
}

*{ box-sizing: border-box; }

html{ background: var(--void); -webkit-text-size-adjust: 100%; }

body{
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--void);
  color: var(--paper);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;              /* the field is the page; nothing scrolls */
  overscroll-behavior: none;
}
::selection{ background: var(--signal); color: var(--ink); }

/* The deep field the canvas sits on: one cool core, a violet low on the left
   and a trace of teal high on the right, so the dark is never flat. */
#field{
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  background:
    radial-gradient(120% 95% at 50% 46%, #0C0A1C 0%, rgba(7,5,15,0.2) 48%, transparent 74%),
    radial-gradient(60% 55% at 8% 86%, rgba(124,77,255,0.10) 0%, transparent 70%),
    radial-gradient(55% 50% at 92% 12%, rgba(47,224,199,0.07) 0%, transparent 72%),
    var(--void);
}

/* A soft edge on the whole composition, so the rooms feel held rather than
   scattered. Drawn over the canvas, under everything you can touch. */
.vignette{
  position: fixed;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(115% 100% at 50% 50%, transparent 52%, rgba(3,2,8,0.72) 100%);
}

.sr-only{
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}

/* ============================================================ THE FOYER === */

.foyer{
  position: relative;
  z-index: 2;
  height: 100vh;
  height: 100dvh;
}

/* ------------------------------------------------------------ the core --- */

.core{
  position: absolute;
  left: 50%; top: 47%;
  transform: translate(-50%, -50%);
  width: min(40rem, 86vw);
  text-align: center;
  pointer-events: none;         /* the field behind stays reachable */
}
.core > *{ pointer-events: auto; }

.wordmark{
  font-family: var(--font-display);
  text-transform: uppercase;
  font-weight: 700;
  /* Sized against Arial, the widest thing in the display stack — on a
     machine with Arial Narrow or Roboto Condensed it simply sits narrower.
     ENTROPIC·LABS has no space in it and cannot wrap, so the ceiling has to
     assume the worst case rather than the good one. */
  font-size: clamp(1.85rem, 4.6vw, 3.7rem);
  letter-spacing: 0.045em;
  line-height: 1;
  margin: 0;
  text-wrap: balance;
  text-shadow:
    0 0 30px rgba(124,77,255,0.26),
    0 0 96px rgba(47,224,199,0.09);
}
.wordmark .dot{
  color: var(--signal);
  text-shadow: 0 0 18px rgba(255,63,160,0.6);
}

.creed{
  margin: 1.05rem auto 0;
  max-width: 30ch;
  color: #DCD6EE;
  font-size: clamp(0.98rem, 0.5vw + 0.85rem, 1.12rem);
}

.invite{
  margin: 1.9rem 0 0;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ash);
}
.invite .caret{
  display: inline-block;
  width: 0.5em; height: 1em;
  margin-left: 0.45em;
  vertical-align: -0.14em;
  background: var(--trace);
  opacity: 0.85;
  animation: caret 1.5s steps(1) infinite;
}
@keyframes caret{ 0%,55%{ opacity: 0.85; } 56%,100%{ opacity: 0; } }

/* ------------------------------------------------------- the four rooms --- */

.realms{ margin: 0; }
.realms ul{
  list-style: none;
  margin: 0;
  padding: 0;
}

.realm{
  position: absolute;
  left: var(--x);
  top: var(--y);
  transform: translate(-50%, -50%);
  width: min(15.5rem, 26vw);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.85rem;
  padding: 0.9rem 0.6rem 1rem;
  color: inherit;
  text-decoration: none;
  text-align: center;
  border-radius: 3px;
  /* the lift on hover rides the `translate` property rather than `transform`,
     because the idle drift below is a transform animation and an animation
     beats a plain declaration outright */
  translate: 0 0;
  transition: translate 0.5s cubic-bezier(.2,.75,.3,1);
}

/* the halo: a soft field of the room's own colour, dim until you come near */
.realm::before{
  content: "";
  position: absolute;
  left: 50%; top: 2.6rem;
  width: 15rem; height: 15rem;
  transform: translate(-50%, -50%) scale(0.72);
  border-radius: 50%;
  background: radial-gradient(circle, var(--glow) 0%, transparent 68%);
  opacity: 0.10;
  filter: blur(6px);
  transition: opacity 0.45s ease, transform 0.55s cubic-bezier(.2,.75,.3,1);
  pointer-events: none;
}

.realm-mark{
  position: relative;
  width: 3.4rem; height: 3.4rem;
  display: grid;
  place-items: center;
  color: var(--glow);
  /* only the symbol wanders when idle. The name under it and the area you
     click stay put — a target that drifts is a target you have to chase. */
  animation: mark-drift var(--drift, 19s) ease-in-out var(--drift-delay, 0s) infinite alternate;
}
.realm-mark svg{
  width: 100%; height: 100%;
  overflow: visible;
  display: block;
}

.realm-body{ display: block; }

.realm-index{
  display: block;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.24em;
  color: var(--ash);
  opacity: 0.75;
  transition: color 0.3s ease, opacity 0.3s ease;
}
.realm-name{
  display: block;
  margin-top: 0.35rem;
  font-family: var(--font-display);
  text-transform: uppercase;
  font-weight: 700;
  font-size: clamp(1rem, 0.7vw + 0.85rem, 1.32rem);
  letter-spacing: 0.05em;
  line-height: 1.1;
  transition: text-shadow 0.4s ease;
}

/* the one line each room is willing to say about itself, held back until
   somebody asks for it by hovering, focusing or tapping */
.realm-line{
  display: block;
  margin-top: 0.5rem;
  max-width: 26ch;
  margin-inline: auto;
  font-size: 0.86rem;
  line-height: 1.5;
  color: var(--ash);
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity 0.4s ease, transform 0.4s ease;
}

@media (hover: hover){
  .realm:hover{ translate: 0 -6px; }
}
.realm:hover::before,
.realm:focus-visible::before,
.realm.is-near::before{
  opacity: 0.30;
  transform: translate(-50%, -50%) scale(1);
}
.realm:hover .realm-line,
.realm:focus-visible .realm-line,
.realm.is-near .realm-line{
  opacity: 1;
  transform: none;
}
.realm:hover .realm-index,
.realm:focus-visible .realm-index,
.realm.is-near .realm-index{ color: var(--glow); opacity: 1; }
.realm:hover .realm-name,
.realm:focus-visible .realm-name{ text-shadow: 0 0 22px var(--glow); }

.realm:focus{ outline: none; }
.realm:focus-visible{
  outline: 2px solid var(--glow);
  outline-offset: 6px;
}

@keyframes mark-drift{
  from{ transform: translate3d(0, 0, 0); }
  to{   transform: translate3d(var(--dx, 6px), var(--dy, -9px), 0); }
}

/* --- where each room hangs, and what colour it burns ---------------------
   Asymmetric on purpose: the composition should look found rather than laid
   out. --in staggers the arrival, --dx/--dy/--drift give each room its own
   slow wander so the map is never twice in the same state. -------------- */

.realm--observatory{
  --x: 24%; --y: 17%;
  --glow: var(--trace);
  --in: 1.25s;
  --dx: 8px; --dy: -10px; --drift: 21s; --drift-delay: -4s;
}
.realm--studio{
  --x: 81%; --y: 29%;
  --glow: var(--signal);
  --in: 1.45s;
  --dx: -9px; --dy: 8px; --drift: 24s; --drift-delay: -11s;
}
.realm--game{
  --x: 67%; --y: 80%;
  --glow: var(--violet);
  --in: 1.65s;
  --dx: 7px; --dy: 9px; --drift: 18s; --drift-delay: -7s;
}
.realm--butterfly{
  --x: 19%; --y: 68%;
  --glow: var(--ember);
  --in: 1.85s;
  --dx: -6px; --dy: -8px; --drift: 26s; --drift-delay: -15s;
}

/* --- the marks, each moving in the idiom of its own room ----------------- */

/* Observatory: a body on a slow orbit. One turn a minute — you notice it has
   moved rather than watching it move. */
.mark-orbit{ transform-origin: 24px 24px; animation: orbit 62s linear infinite; }
@keyframes orbit{ to{ transform: rotate(360deg); } }
.mark-twinkle{ animation: twinkle 6s ease-in-out infinite; transform-origin: 24px 24px; }
@keyframes twinkle{ 0%,100%{ opacity: 0.95; transform: scale(1); } 50%{ opacity: 0.55; transform: scale(0.86); } }

/* Studio: seven bands off a meter, moving as a meter does — never together.
   fill-box puts each band's origin on its own foot rather than on the middle
   of the viewBox, so they grow off the baseline instead of sliding. */
.mark-bar{
  transform-box: fill-box;
  transform-origin: 50% 100%;
  animation: band 1.9s ease-in-out infinite alternate;
}
.mark-bar:nth-child(1){ animation-duration: 1.7s; animation-delay: -0.9s; }
.mark-bar:nth-child(2){ animation-duration: 2.3s; animation-delay: -1.6s; }
.mark-bar:nth-child(3){ animation-duration: 1.3s; animation-delay: -0.4s; }
.mark-bar:nth-child(4){ animation-duration: 2.7s; animation-delay: -2.2s; }
.mark-bar:nth-child(5){ animation-duration: 1.5s; animation-delay: -0.2s; }
.mark-bar:nth-child(6){ animation-duration: 2.1s; animation-delay: -1.1s; }
.mark-bar:nth-child(7){ animation-duration: 1.9s; animation-delay: -1.4s; }
@keyframes band{ from{ transform: scaleY(0.22); } to{ transform: scaleY(1); } }
.realm--studio:hover .mark-bar{ animation-duration: 0.62s; }

/* Game Room: pixels that drop out and come back, one at a time. Nine of
   them, on nine different clocks, so the diamond is never quite whole. */
.mark-px{ animation: px-flicker 7s steps(1) infinite; }
.mark-px:nth-child(2){ animation-delay: -0.8s; }
.mark-px:nth-child(3){ animation-delay: -1.6s; }
.mark-px:nth-child(4){ animation-delay: -2.3s; }
.mark-px:nth-child(5){ animation-delay: -3.1s; }
.mark-px:nth-child(6){ animation-delay: -3.9s; }
.mark-px:nth-child(7){ animation-delay: -4.7s; }
.mark-px:nth-child(8){ animation-delay: -5.4s; }
.mark-px:nth-child(9){ animation-delay: -6.2s; }
@keyframes px-flicker{ 0%,92%{ opacity: 1; } 93%,96%{ opacity: 0.12; } 97%,100%{ opacity: 1; } }

/* Butterfly Trails: a wingbeat slow enough to be a breath. */
.mark-wing{ transform-origin: 24px 24px; animation: wingbeat 4.6s ease-in-out infinite; }
@keyframes wingbeat{ 0%,100%{ transform: scaleX(1); } 50%{ transform: scaleX(0.42); } }
.realm--butterfly:hover .mark-wing{ animation-duration: 1.1s; }

/* ==================================================== THE SILL (footer) === */

.sill{
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 3;
  height: var(--sill-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0 clamp(0.9rem, 3vw, 2rem);
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ash);
}
.sill .est{ opacity: 0.55; }
.sill .readout{
  opacity: 0.34;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  letter-spacing: 0.1em;
}

/* S = k log W. Boltzmann's, on his headstone in Vienna, and the reason this
   place is called what it is. Nearly invisible until somebody goes looking. */
.entropy-note{ position: relative; display: inline-flex; }
.entropy{
  appearance: none;
  background: none;
  border: 0;
  padding: 0.45rem 0.2rem;
  margin: 0;
  font: inherit;
  letter-spacing: 0.1em;
  color: var(--paper);
  opacity: 0.12;
  cursor: help;
  transition: opacity 0.4s ease, color 0.4s ease;
}
.entropy:hover, .entropy:focus-visible{ opacity: 0.85; color: var(--trace); }
.entropy:focus-visible{ outline: 1px solid var(--trace); outline-offset: 4px; }
.entropy-note .gloss{
  position: absolute;
  bottom: 130%;
  left: 50%;
  transform: translate(-50%, 6px);
  width: max-content;
  max-width: min(24rem, 72vw);
  padding: 0.5rem 0.75rem;
  background: rgba(9,7,18,0.96);
  border: 1px solid var(--hairline);
  border-left: 2px solid var(--trace);
  color: var(--ash);
  font-size: 0.62rem;
  letter-spacing: 0.06em;
  text-transform: none;
  line-height: 1.6;
  text-align: left;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.35s ease, transform 0.35s ease;
}
.entropy-note:hover .gloss,
.entropy-note:focus-within .gloss{ opacity: 1; transform: translate(-50%, 0); }

/* what the field says back, when something in it is worth saying */
.whisper{
  position: fixed;
  left: 50%;
  bottom: calc(var(--sill-h) + 1.1rem);
  transform: translateX(-50%) translateY(6px);
  z-index: 3;
  max-width: min(30rem, 82vw);
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  line-height: 1.7;
  color: var(--trace);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.6s ease, transform 0.6s ease;
}
.whisper.on{ opacity: 0.8; transform: translateX(-50%) translateY(0); }

/* ================================================== THE WAY OUT (exit) === */

/* The short film between here and there: 300–700ms of the room you picked,
   drawn over everything, then the page changes underneath it. */
.curtain{
  position: fixed;
  inset: 0;
  z-index: 40;
  pointer-events: none;
  opacity: 0;
  transition: opacity 180ms ease;
}
.curtain.on{ opacity: 1; pointer-events: auto; }
.curtain canvas{ position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

body.leaving .foyer{
  transition: opacity 340ms ease, transform 340ms cubic-bezier(.4,0,.6,1);
  opacity: 0;
  transform: scale(1.03);
}
body.leaving .sill, body.leaving .whisper{ transition: opacity 240ms ease; opacity: 0; }

/* ================================================ ARRIVING AT THE FOYER === */

/* The wordmark first, then the traces the canvas draws, then the rooms —
   in the order the eye should take them. `both` keeps the no-JS page intact:
   with scripting off there is no field, but every room still lands. */
.core .wordmark{ animation: rise 900ms cubic-bezier(.16,.84,.44,1) 120ms both; }
.core .creed{    animation: rise 900ms cubic-bezier(.16,.84,.44,1) 420ms both; }
.core .invite{   animation: rise 900ms cubic-bezier(.16,.84,.44,1) 900ms both; }
.realm{ opacity: 0; animation: room-in 1s cubic-bezier(.16,.84,.44,1) var(--in, 1.2s) both; }
.sill{ animation: rise 900ms ease 1.9s both; }

@keyframes rise{
  from{ opacity: 0; transform: translateY(12px); }
  to{ opacity: 1; transform: none; }
}
@keyframes room-in{
  from{ opacity: 0; }
  to{ opacity: 1; }
}

/* ============================================================ NARROWER === */

/* Laptops and small desktops: pull the rooms in off the edges. */
@media (max-width: 1100px){
  .realm{ width: min(13.5rem, 24vw); }
  .realm--studio{ --x: 83%; }
  .realm--butterfly{ --x: 17%; }
}

/* Short and wide (a laptop in landscape, a tablet on its side): the rooms
   close in vertically so nothing collides with the wordmark. */
@media (min-width: 821px) and (max-height: 700px){
  .core{ top: 48%; }
  .realm{ padding-top: 0.4rem; gap: 0.6rem; }
  .realm-mark{ width: 2.7rem; height: 2.7rem; }
  .realm--observatory{ --y: 15%; }
  .realm--studio{ --y: 26%; }
  .realm--game{ --y: 79%; }
  .realm--butterfly{ --y: 67%; }
  .realm-line{ font-size: 0.8rem; }
}

/* ================================================== PHONES AND TABLETS === */

/* Not a smaller version of the map — the same four rooms, unrolled into a
   trail you walk down. The canvas keeps drawing the field and re-reads where
   the rooms are, so the trail follows the scroll. */
@media (max-width: 820px){
  body{ overflow-y: auto; overflow-x: hidden; }

  .foyer{
    height: auto;
    min-height: 100vh;
    min-height: 100dvh;
    padding: 0 0 calc(var(--sill-h) + 3rem);
    /* A tablet in portrait has more height than the trail needs. Centring is
       safe here because the container grows to fit whenever the trail is the
       taller of the two — so nothing is ever pushed off the top. */
    display: flex;
    flex-direction: column;
    justify-content: center;
  }

  .core{
    position: static;
    transform: none;
    width: auto;
    padding: clamp(3rem, 11vh, 5.5rem) 1.4rem clamp(1.8rem, 5vh, 2.8rem);
    margin: 0 auto;
    max-width: 32rem;
  }

  .wordmark{ font-size: clamp(2rem, 9.5vw, 3.4rem); }

  .realms ul{
    display: flex;
    flex-direction: column;
    gap: clamp(1.6rem, 5vw, 2.4rem);
    padding: 0 1.1rem;
    max-width: 34rem;
    margin: 0 auto;
  }

  .realm{
    position: relative;
    left: auto; top: auto;
    transform: none;
    width: auto;
    min-height: 5.5rem;
    display: grid;
    grid-template-columns: 3.6rem 1fr;
    align-items: center;
    gap: 1.05rem;
    text-align: left;
    padding: 1.05rem 1.1rem;
    border: 1px solid var(--hairline);
    border-left: 2px solid var(--glow);
    background: linear-gradient(100deg, rgba(19,14,34,0.58), rgba(11,8,20,0.18));
    animation: room-in 800ms cubic-bezier(.16,.84,.44,1) var(--in, 1.1s) both;
  }
  /* the trail meanders rather than running straight down the page — the
     offset belongs on the list item, since each room is its item's only
     child and would otherwise always be :nth-child(1) */
  .realms li:nth-child(even) .realm{ margin-left: clamp(0.7rem, 7vw, 2.6rem); }
  .realms li:nth-child(odd) .realm{ margin-right: clamp(0.7rem, 7vw, 2.6rem); }

  .realm::before{
    left: 2.4rem; top: 50%;
    width: 11rem; height: 11rem;
    opacity: 0.16;
  }
  .realm-mark{ width: 3.6rem; height: 3.6rem; }
  .realm-line{ opacity: 1; transform: none; max-width: none; }
  .realm-index{ color: var(--glow); opacity: 1; }
  .realm:hover{ translate: 0 0; }

  .sill{ background: linear-gradient(rgba(5,4,13,0), rgba(5,4,13,0.92) 55%); }
  .sill .readout{ display: none; }

  .whisper{ bottom: calc(var(--sill-h) + 0.6rem); }
}

@media (max-width: 420px){
  .realms ul{ padding: 0 0.9rem; }
  .realm{ grid-template-columns: 3rem 1fr; gap: 0.85rem; padding: 0.95rem; }
  .realm-mark{ width: 3rem; height: 3rem; }
  .sill{ font-size: 0.56rem; letter-spacing: 0.1em; }
}

/* ====================================================== REDUCED MOTION === */

/* Everything above that moves, stops. The canvas draws one frame and the
   rooms are simply where they are — the page is the same page, held still. */
@media (prefers-reduced-motion: reduce){
  .realm,
  .core .wordmark, .core .creed, .core .invite, .sill,
  .invite .caret, .realm-mark,
  .mark-orbit, .mark-twinkle, .mark-bar, .mark-px, .mark-wing{
    animation: none !important;
  }
  .realm{ opacity: 1; }
  .realm, .realm::before, .realm-line, .realm-index, .realm-name,
  .whisper, .entropy, .entropy-note .gloss, .curtain{ transition: none; }
  .realm-line{ opacity: 1; transform: none; }
  .realm:hover{ translate: 0 0; }
  body.leaving .foyer{ transition: none; }
}
