/* ===========================================================================
   Elysian Realms — the site
   ---------------------------------------------------------------------------
   The palette is the game's own Elysian theme, lifted from style.css in the
   project root so the site and the thing it is selling are the same colour.
   The roles hold here too: --gold is the realm, --frost is the Veil and the
   ice, --purple is the menus. No framework, no build step, no dependencies —
   the same rule the game is built on.
   ======================================================================== */

@font-face{
  font-family:'Press Start 2P'; font-style:normal; font-weight:400; font-display:swap;
  src:url('fonts/press-start-2p-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Press Start 2P'; font-style:normal; font-weight:400; font-display:swap;
  src:url('fonts/press-start-2p-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face{
  font-family:'VT323'; font-style:normal; font-weight:400; font-display:swap;
  src:url('fonts/vt323-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:'VT323'; font-style:normal; font-weight:400; font-display:swap;
  src:url('fonts/vt323-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

:root{
  --bg:#0e131c;
  --panel:#1a2230;
  --panel-sunk:#141b27;
  --panel-line:#324058;
  --ink:#eef1f6;
  --ink-soft:#c1cbdc;
  --ghost:#6b76a0;
  --gold:#e3b94c;
  --gold-dim:#8a6a1c;
  --frost:#6fb8dd;
  --purple:#8a6fc4;
  --ember:#f0a93c;

  --display:'Press Start 2P', ui-monospace, monospace;
  --body:'VT323', ui-monospace, 'Courier New', monospace;

  --measure:62ch;
  --gutter:clamp(16px, 5vw, 56px);
}

*{box-sizing:border-box;}
html{scroll-behavior:smooth;}
@media (prefers-reduced-motion: reduce){ html{scroll-behavior:auto;} }

body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font-family:var(--body);
  /* VT323 runs small and narrow, so it needs a size a body font would not. */
  font-size:clamp(20px, 1.15vw + 16px, 25px);
  line-height:1.45;
  -webkit-font-smoothing:antialiased;
}

h1, h2, .eyebrow, .btn, .player-head, .facts b, .realms b, .foot-mark{
  font-family:var(--display);
  font-weight:400;
  letter-spacing:0.04em;
  line-height:1.5;
}

a{color:var(--frost); text-decoration-thickness:1px; text-underline-offset:3px;}
a:hover{color:var(--gold);}

.sr, .skip:not(:focus){
  position:absolute; width:1px; height:1px; margin:-1px; padding:0;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}
.skip:focus{
  position:fixed; top:10px; left:10px; z-index:99; width:auto; height:auto;
  clip:auto; padding:10px 14px; background:var(--panel); border:2px solid var(--gold);
  color:var(--ink); font-family:var(--display); font-size:0.5rem;
}
:focus-visible{outline:3px solid var(--gold); outline-offset:3px;}

/* ---------------------------------------------------------------- hero --- */
.hero{
  position:relative;
  min-height:min(92vh, 820px);
  display:grid; align-items:center;
  padding:clamp(64px, 12vh, 140px) var(--gutter);
  overflow:hidden;
  border-bottom:3px solid var(--panel-line);
}
.hero-scene{position:absolute; inset:0; z-index:0;}
/* The courses were shouting over the window they are there to frame. */
.bricks{opacity:0.45;}
.arch{
  position:absolute; inset:0; width:100%; height:100%;
  /* Pixel art: never let the browser smooth it. */
  image-rendering:pixelated; shape-rendering:crispEdges;
}
.vignette{
  position:absolute; inset:0;
  background:radial-gradient(120% 86% at 50% 46%, transparent 30%, rgba(8,11,18,0.86) 100%);
}
.hero-plate{
  position:relative; z-index:1;
  /* Sits INSIDE the window opening, the way the menu panel does in the game. */
  /* A definite width, not just a cap: inline-size containment stops an
     element sizing itself from its contents, so a max-width alone collapses
     the plate to nothing. */
  width:min(640px, 94%);
  max-width:100%;
  /* The title measures itself against THIS, not against the window. */
  container-type:inline-size;
  margin-inline:auto;
  padding:clamp(22px, 4vw, 38px);
  background:rgba(14,19,28,0.78);
  border:3px solid var(--panel-line);
  backdrop-filter:blur(2px);
  text-align:center;
}
.eyebrow{
  margin:0 0 14px; font-size:0.5rem; color:var(--gold);
  letter-spacing:0.14em; text-transform:lowercase;
}
.hero h1{
  margin:0 0 20px;
  /* cqw = 1% of the plate's own width. "Elysian Realms" is 14 characters in a
     monospaced pixel face, so 7.4cqw fills the plate without touching either
     border, and the clamp keeps it readable on a phone and from growing silly
     on a desktop. The old 4.6vw knew nothing about the box it was inside. */
  font-size:clamp(0.92rem, 7.4cqw, 2.05rem);
  color:var(--ink);
  text-wrap:balance;
  text-shadow:0 3px 0 #0a0d14, 0 0 26px rgba(227,185,76,0.16);
}
.tagline{margin:0 0 26px; color:var(--ink-soft); font-size:1.12em;}
.cta-row{display:flex; gap:12px; flex-wrap:wrap; justify-content:center;}
.cta-note{margin:16px 0 0; font-size:0.86em; color:var(--ghost);}

.btn{
  display:inline-block; padding:13px 20px;
  font-size:0.5rem;
  background:var(--panel); border:3px solid var(--panel-line); color:var(--ink);
  text-decoration:none; cursor:pointer;
}
.btn:hover, .btn:focus-visible{border-color:var(--frost); color:var(--ink);}
.btn-gold{background:var(--gold-dim); border-color:var(--gold); color:#fff8e6;}
.btn-gold:hover, .btn-gold:focus-visible{background:#9d7a20; border-color:#f3cf6c; color:#fff8e6;}
.btn[aria-disabled="true"]{opacity:0.55; cursor:not-allowed;}

/* The torches breathe. Three sine terms in the game; two here, at sizes that
   do not share a period, which is what stops it reading as a pulse. */
.flame{transform-origin:50% 100%; transform-box:fill-box; animation:flicker 1.7s ease-in-out infinite;}
.flame-core{transform-origin:50% 100%; transform-box:fill-box; animation:flicker 1.1s ease-in-out infinite reverse;}
.torch-r .flame{animation-duration:1.9s; animation-delay:-0.6s;}
.torch-r .flame-core{animation-duration:1.3s; animation-delay:-0.3s;}
.torch-glow{animation:glow 2.3s ease-in-out infinite;}
.glow-r{animation-duration:2.9s; animation-delay:-0.9s;}
@keyframes flicker{
  0%,100%{transform:scaleY(1)   scaleX(1);    opacity:0.92;}
  34%    {transform:scaleY(1.14) scaleX(0.92); opacity:1;}
  67%    {transform:scaleY(0.9)  scaleX(1.06); opacity:0.84;}
}
@keyframes glow{ 0%,100%{opacity:0.75;} 50%{opacity:1;} }

/* Snow lives in the svg now, inside the window's clip. In USER UNITS, which
   is the point: the old one fell 110vh, the viewport's height, inside a hero
   that is taller than the viewport on most screens — so on a short window the
   flakes stopped partway down and the fall read as broken. The window is 90
   units tall, the travel is 104, and that is true at every rendered size.
   transform-box:view-box so a translate is measured in those units. */
#snow circle{
  fill:#e8f1fb;
  transform-box:view-box;
  animation:fall linear infinite;
  will-change:transform;
}
@keyframes fall{
  from{transform:translate(0, 0);}
  to  {transform:translate(3px, 104px);}
}
@media (prefers-reduced-motion: reduce){
  .flame, .flame-core, .torch-glow{animation:none;}
  #snow{display:none;}
}

/* --------------------------------------------------------------- bands --- */
.band{
  max-width:var(--measure);
  margin:0 auto;
  padding:clamp(56px, 9vh, 96px) var(--gutter);
}
.band-wide{max-width:1100px;}
.band-quiet{background:var(--panel-sunk); max-width:none; border-block:3px solid var(--panel-line);}
.band-quiet > *{max-width:var(--measure); margin-inline:auto;}
.band-cta{background:var(--panel); max-width:none; border-block:3px solid var(--panel-line); text-align:center;}
.band-cta > *{max-width:var(--measure); margin-inline:auto;}

h2{
  margin:0 0 22px;
  font-size:clamp(0.62rem, 2.1vw, 0.86rem);
  color:var(--gold);
  text-wrap:balance;
}
.lede{margin:0 0 20px; color:var(--ink-soft); font-size:1.12em;}
p{margin:0 0 16px;}

/* the four numbers */
.facts{
  list-style:none; margin:30px 0 0; padding:0;
  display:grid; gap:14px;
  grid-template-columns:repeat(auto-fit, minmax(230px, 1fr));
}
.facts li{
  display:flex; align-items:baseline; gap:14px;
  padding:14px 16px;
  background:var(--panel); border:3px solid var(--panel-line);
}
.facts b{flex:0 0 auto; font-size:0.78rem; color:var(--gold); line-height:1;}
.facts span{color:var(--ink-soft); font-size:0.94em;}

/* the road */
.realms{list-style:none; margin:0; padding:0; counter-reset:realm;}
.realms li{
  display:grid; grid-template-columns:2.6rem 1fr; gap:4px 16px;
  padding:16px 0; border-top:2px solid var(--panel-line);
}
.realms li:last-child{border-bottom:2px solid var(--panel-line);}
.realms i{
  grid-row:span 2; align-self:center;
  font-style:normal; font-family:var(--display); font-size:0.52rem;
  color:var(--gold-dim); text-align:right;
}
.realms b{font-size:0.5rem; color:var(--ink); line-height:1.6;}
.realms span{color:var(--ink-soft); font-size:0.94em;}
.realms .locked b{color:var(--ghost);}
.realms .locked span{color:var(--ghost);}

/* --------------------------------------------------------------- pitch ---
   The three formats read as three things, not three rows of a table: each
   one gets its own left rule in its own colour, which is the only place on
   the page colour is used to mean something. The pillars underneath are
   deliberately plainer — the formats are the argument, these are the
   support. */
.formats{list-style:none; margin:26px 0 0; padding:0;}
.formats li{
  display:grid; gap:6px;
  padding:16px 0 16px 18px; margin:0 0 14px;
  border-left:4px solid var(--panel-line);
  background:linear-gradient(90deg, var(--panel) 0%, transparent 70%);
}
.formats b{
  font-family:var(--display); font-size:0.52rem; line-height:1.6;
  color:var(--ink); letter-spacing:0.02em;
}
.formats span{color:var(--ink-soft); font-size:0.96em;}
.formats .fmt-harder{border-left-color:var(--gold);}
.formats .fmt-harder b{color:var(--gold);}
.formats .fmt-cata{border-left-color:var(--purple);}
.formats .fmt-cata b{color:var(--purple);}

.pillars{
  display:grid; gap:18px; margin:30px 0 0;
  /* 320, not 260: four items at 260 fit three to a row and leave the
     fourth stranded on its own. At 320 they pair up 2x2 on a wide screen
     and stack on a narrow one, which is the shape four things want. */
  grid-template-columns:repeat(auto-fit, minmax(320px, 1fr));
}
.pillars h3{
  margin:0 0 8px; font-family:var(--display); font-size:0.46rem; line-height:1.7;
  color:var(--gold); letter-spacing:0.02em;
}
.pillars p{margin:0; color:var(--ink-soft); font-size:0.94em;}
.pillars em{font-style:normal; color:var(--ink);}

.why-try{margin:28px 0 0; padding-top:18px; border-top:2px solid var(--panel-line); color:var(--ink-soft);}

/* -------------------------------------------------------------- trailer --- */
.video-frame{
  position:relative;
  border:3px solid var(--panel-line); background:#000;
  aspect-ratio:16 / 9;
}
.video-frame video{display:block; width:100%; height:100%; object-fit:contain; background:#000;}
.video-missing{
  position:absolute; inset:0;
  display:grid; place-content:center; gap:10px; text-align:center;
  padding:24px; background:var(--panel-sunk); color:var(--ink-soft);
}
.video-missing b{font-family:var(--display); font-size:0.5rem; color:var(--gold);}
.video-missing p{margin:0; max-width:46ch;}
code{
  font-family:ui-monospace, 'Courier New', monospace; font-size:0.78em;
  background:var(--bg); border:1px solid var(--panel-line); padding:1px 5px;
}

/* ----------------------------------------------------------------- film ---
   The trailer sits in a frame the width of the column, with the video filling
   it at its own 16:9. aspect-ratio rather than the old padding-top trick, so
   the poster, the controls and the black bars cannot disagree about where the
   bottom is while the file is still loading. */
.band-film{ padding-bottom:clamp(40px, 7vh, 72px); }
.film-frame{
  position:relative; width:100%; aspect-ratio:16 / 9;
  background:#06080d; border:3px solid var(--panel-line);
  box-shadow:0 10px 0 rgba(0,0,0,0.35);
}
.film-frame video{ display:block; width:100%; height:100%; background:#06080d; }
.film-note{ margin:14px 0 0; color:var(--ghost); font-size:0.9em; max-width:var(--measure); }

/* --------------------------------------------------------------- player ---
   Transcribed from the games own #music-tab-panel, rule for rule. Somebody who
   has played the game should recognise this panel without being told, so the
   numbers below are the games numbers and not a web designers idea of them:
   the 290px panel, the 8px seek bar with its 4px gold knob, the gold name over
   the uppercase subtitle, the three borderless transport buttons with the play
   face gold and a size larger.

   The variables the game sets globally are scoped to the rail here rather than
   added to :root, so nothing else on the page can pick them up by accident.
   ======================================================================== */
#music-rail{
  /* One of the game's rems. The game sets html{font-size:17px}; a web page
     gets the browser's 16. Every size in this panel is written in rem, so
     without this the whole thing came out 6% small - near enough to look
     right and not near enough to BE right. Multiplying rather than moving
     the site's root keeps the correction inside the rail, where it belongs:
     nothing else on the page wants the game's scale. */
  --u:calc(17 / 16 * 1rem);
  --font-display:var(--display);
  --bevel-lt:rgba(255,255,255,0.16);
  --pixel-shadow:4px 4px 0 0 rgba(0,0,0,0.55);
  --frame-glow:rgba(138,111,196,0.25);
}
.player{ margin:0; }
.player h4{
  margin:0 !important; flex:1;
  font-family:var(--font-display); font-size:calc(0.42 * var(--u)); letter-spacing:0.1em;
  text-transform:uppercase; color:var(--gold); font-weight:400;
}
.player-head{display:flex; align-items:center; gap:4px; margin:0 0 5px;}
.player-now{margin:0 0 6px; min-height:2.1em;}
.player-now-name{
  font-size:calc(0.86 * var(--u)); font-weight:700; color:var(--gold); line-height:1.15;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.player-now-sub{
  font-size:calc(0.56 * var(--u)); color:#8f9ab4; letter-spacing:0.04em; text-transform:uppercase;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.player-seek{margin:0 0 7px;}
.mp-bar{
  position:relative; height:8px; background:#0d111a; border:2px solid #2d3650; cursor:pointer;
}
.mp-bar:hover{border-color:var(--purple);}
.mp-bar:focus-visible{border-color:var(--gold); outline:none;}
.mp-fill{position:absolute; inset:0 auto 0 0; width:0; background:var(--purple);}
.mp-knob{
  position:absolute; top:-3px; left:0; width:4px; height:10px; margin-left:-2px;
  background:var(--gold); box-shadow:0 0 0 1px #0d111a;
}
.mp-times{
  display:flex; justify-content:space-between; font-size:calc(0.54 * var(--u)); color:#6f7a93;
  margin-top:3px; font-variant-numeric:tabular-nums;
}
.player-controls{display:flex; gap:5px; justify-content:center; margin:0 0 6px;}
.player-controls button{
  flex:0 0 auto; padding:2px 9px; line-height:0;
  background:none; border:none; color:var(--ink-soft); cursor:pointer; box-shadow:none;
}
/* The glyph never takes the click: the button is the control, the drawing
   inside it is scenery. Letting it be an event target is what made the centre
   of the games play button feel dead while its edges worked. */
.player-controls button svg{display:block; image-rendering:pixelated; pointer-events:none;}
.player-controls button:hover, .player-controls button:focus-visible{color:var(--gold); background:none;}
.player-controls button:active{transform:translateY(1px);}
#mp-play{color:var(--gold) !important; padding:0 11px !important;}
/* The play order: a small square on the heading line, not a fourth transport
   button. It was a wide text label reading "Loop all"; the game uses one glyph
   and the tooltip carries the words. */
.mp-mode{
  flex:0 0 auto; width:26px; height:22px; padding:0 4px; line-height:1;
  background:#171d2a; border:2px solid #2d3650; color:var(--gold);
  font-size:calc(0.78 * var(--u)); cursor:pointer;
}
.mp-mode:hover, .mp-mode:focus-visible{border-color:var(--gold); background:rgba(240,207,107,0.18);}
#mp-list-toggle{
  display:block; width:100%; text-align:left; padding:5px 8px; margin:0 0 6px;
  background:rgba(16,20,30,0.85); border:2px solid #2d3650; color:#c1cbdc;
  font-family:var(--body); font-size:calc(0.62 * var(--u)); letter-spacing:0.06em;
  text-transform:uppercase; cursor:pointer;
}
#mp-list-toggle:hover, #mp-list-toggle:focus-visible{border-color:var(--purple); color:var(--gold);}
#mp-list-caret{display:inline-block; transition:transform 0.18s ease-out;}
#mp-list-toggle[aria-expanded="true"] #mp-list-caret{transform:rotate(90deg);}
@media (prefers-reduced-motion: reduce){ #mp-list-caret{transition:none;} }
.player-list.collapsed{display:none;}
.mt-item{
  display:block; width:100%; text-align:left; margin:0 0 4px; padding:6px 8px;
  background:rgba(16,20,30,0.85); border:2px solid #2d3650; color:var(--ink);
  font-family:var(--body); font-size:calc(0.72 * var(--u)); line-height:1.25; cursor:pointer;
}
.mt-item:hover, .mt-item:focus-visible{background:var(--frame-glow); border-color:var(--purple);}
.mt-item.on{border-color:var(--gold); background:rgba(240,207,107,0.16);}
.mt-name{display:block; font-weight:700;}
.mt-sub{display:block; font-size:calc(0.6 * var(--u)); color:#a9b2c8;}
.mt-item.on .mt-sub{color:#e8d9a8;}
.player-note{margin:6px 0 0; font-size:calc(0.58 * var(--u)); color:#6f7a93; line-height:1.3;}

/* --------------------------------------------------------------- signup --- */
/* The bot trap in the sign-up form. Not display:none - that is the one
   approach that fails, since a bot reads the markup either way and some
   providers treat a hidden-by-display field as suspicious in itself. Pushed
   off-canvas and hidden from assistive tech instead, which is what Mailchimp
   and everyone else does. */
.signup-trap{position:absolute; left:-5000px; width:1px; height:1px; overflow:hidden;}
.signup{display:flex; gap:10px; flex-wrap:wrap; justify-content:center; margin-top:24px;}
.signup input{
  flex:1 1 260px; max-width:360px; padding:12px 14px;
  background:var(--panel-sunk); border:3px solid var(--panel-line);
  color:var(--ink); font-family:var(--body); font-size:1em;
}
.signup input::placeholder{color:var(--ghost);}
.signup input:focus{outline:none; border-color:var(--gold);}
.signup-note{margin-top:14px; color:var(--gold); font-size:0.92em;}

/* --------------------------------------------------------------- footer --- */
footer{
  padding:clamp(40px, 7vh, 64px) var(--gutter);
  border-top:3px solid var(--panel-line);
  text-align:center; color:var(--ghost);
}
footer p{margin:0 0 10px;}
.foot-mark{font-size:0.5rem; color:var(--ink-soft); letter-spacing:0.08em;}
.foot-links a{color:var(--ink-soft);}
.foot-fine{font-size:0.82em; margin-top:18px;}
.foot-fine a{color:var(--ghost);}

@media (max-width: 560px){
  .realms li{grid-template-columns:2rem 1fr;}
}


/* ===========================================================================
   The inner pages — press kit, privacy — and the screenshot strip
   ---------------------------------------------------------------------------
   They share everything with the home page except the hero, which they do not
   have: a plain head band instead, so the eye starts in the same place.
   ======================================================================== */
.page-head{
  padding:clamp(48px, 9vh, 92px) var(--gutter) clamp(28px, 5vh, 48px);
  border-bottom:3px solid var(--panel-line);
  background:var(--panel-sunk);
  text-align:center;
}
.page-head .eyebrow a{color:var(--gold); text-decoration:none; letter-spacing:0.14em;}
.page-head .eyebrow a:hover{color:var(--ink);}
.page-head h1{
  margin:0 0 16px; font-family:var(--display); font-weight:400;
  font-size:clamp(0.8rem, 3.4vw, 1.3rem); text-wrap:balance;
}
.page-head .tagline{margin:0 auto; max-width:var(--measure); color:var(--ink-soft);}

.page h3{
  margin:30px 0 10px; font-family:var(--display); font-weight:400;
  font-size:clamp(0.44rem, 1.5vw, 0.54rem); color:var(--frost); line-height:1.6;
}
.page .band h2{margin-top:0;}
.page .band + .band{padding-top:0;}
.page .band h2:not(:first-child){margin-top:46px;}

blockquote{
  margin:0 0 18px; padding:14px 18px;
  background:var(--panel); border-left:4px solid var(--gold-dim);
  color:var(--ink-soft);
}
blockquote p{margin:0 0 12px;}
blockquote p:last-child{margin:0;}

.fact-sheet{
  display:grid; grid-template-columns:minmax(7.5rem, auto) 1fr; gap:0;
  margin:0; border-top:2px solid var(--panel-line);
}
.fact-sheet dt{
  padding:10px 14px 10px 0; border-bottom:2px solid var(--panel-line);
  font-family:var(--display); font-size:0.38rem; color:var(--gold); line-height:1.7;
}
.fact-sheet dd{
  margin:0; padding:10px 0; border-bottom:2px solid var(--panel-line);
  color:var(--ink-soft);
}
.fine{color:var(--ghost); font-size:0.88em;}

.bullets{margin:0 0 18px; padding-left:1.1em; color:var(--ink-soft);}
.bullets li{margin-bottom:10px;}
.bullets b{color:var(--ink);}

/* The screenshots. One column on a phone, two from tablet up — never three,
   because a 1120x630 frame shown a third of a page wide shows nothing. */
.shot-grid, .shot-strip{
  display:grid; gap:18px; margin-top:24px;
  grid-template-columns:repeat(auto-fit, minmax(min(420px, 100%), 1fr));
}
.shot-grid figure, .shot-strip figure{margin:0;}
.shot-grid img, .shot-strip img{
  display:block; width:100%; height:auto;
  border:3px solid var(--panel-line); background:#000;
  /* Not pixelated. These are 2260px captures shown in a column about a
     fifth that wide, and nearest-neighbour COMING DOWN throws away four of
     every five pixels - the art comes out bitty and the HUD text illegible.
     Pixelated is the right call going up, which is not what happens here. */
  image-rendering:auto;
}
.shot-grid a:hover img, .shot-strip a:hover img{border-color:var(--gold);}
.shot-grid figcaption, .shot-strip figcaption{
  margin-top:8px; color:var(--ghost); font-size:0.88em;
}


/* ===========================================================================
   The music rail
   ---------------------------------------------------------------------------
   The game keeps Music, the Log and the Glossary on tabs down the right edge,
   parked off-screen but for the tab itself. This is that, for the web: fixed
   to the window so it rides the scroll, slid out by hover, by keyboard focus,
   or by a tap — because hover does not exist on a phone and a tab that only
   opens on hover is a tab a phone cannot open.
   ======================================================================== */
#music-rail{
  --tab-w:39.6px;
  position:fixed; z-index:40; right:0; top:50%;
  display:flex; align-items:stretch;
  transform:translateY(-50%) translateX(calc(100% - var(--tab-w)));
  transition:transform 180ms ease-out;
}
/* Hover is gated to real pointers. A tap on a touch screen leaves a sticky
   :hover behind that outlives the tap, so .open came off and :hover held the
   rail open anyway — it would not close on mobile. Touch gets the tap toggle. */
#music-rail.open, #music-rail:focus-within{ transform:translateY(-50%) translateX(0); }
@media (hover: hover) and (pointer: fine){
  #music-rail:hover{ transform:translateY(-50%) translateX(0); }
}
@media (prefers-reduced-motion: reduce){ #music-rail{transition:none;} }

/* The handle: the game's, down to the inset bevel. 39.6px is not a tidy
   number and is not meant to be - it is the game's own --tab-w, and matching
   it is the point. */
#rail-tab{
  flex:0 0 var(--tab-w);
  display:flex; align-items:center; justify-content:center;
  padding:0; cursor:pointer;
  background:#171d2a; color:var(--gold);
  border:3px solid var(--purple); border-right:none;
  box-shadow:var(--pixel-shadow), inset 3px 3px 0 0 var(--bevel-lt);
}
#rail-tab:hover, #rail-tab:focus-visible{background:var(--frame-glow);}
#rail-tab svg{display:block; image-rendering:pixelated; pointer-events:none;}
/* 290px is the game's panel width. It gets a vw cap it does not need there,
   because a phone is narrower than any window the game runs in. */
.rail-body{
  width:min(290px, 84vw);
  max-height:84vh; overflow-y:auto; overflow-x:hidden;
  background:rgba(24,28,40,0.97); border:3px solid var(--purple);
  padding:8px 10px 10px;
  box-shadow:var(--pixel-shadow);
}

/* Out of the way of a narrow window: the tab keeps its edge but the panel
   stops short of filling the screen. */
@media (max-width: 480px){
  #music-rail{--tab-w:32px;}
  .rail-body{width:min(270px, 78vw);}
}
/* It sits over the page, so it must not sit over the page's own focus ring. */
#music-rail *:focus-visible{outline-offset:1px;}

/* ---- the logo as a mark ---- */
.mark{
  /* Was 88-124px in a plate with a great deal of nothing around it. */
  display:block; height:clamp(138px, 27cqw, 206px); width:auto; margin:0 auto 6px;
  image-rendering:pixelated;
}
.mark-sm{
  display:inline-block; vertical-align:middle; height:34px; width:auto;
  margin-right:9px; image-rendering:pixelated;
}


/* ===========================================================================
   One column, one left edge  (fix, 2026-10-15)
   ---------------------------------------------------------------------------
   Every band set its own width — .band at 62ch, .band-wide at 1100px, and the
   full-bleed bands centring their children at 62ch inside a 100% parent. Three
   different widths means three different left edges, so heading, paragraph and
   screenshot each started somewhere else down the page and the whole thing read
   as misaligned.
   One container width for every section; prose still capped at a readable
   measure INSIDE it, media free to fill it.
   ======================================================================== */
:root{ --col:920px; }
.band, .band-wide{ max-width:var(--col); margin-inline:auto; }
.band-quiet > *, .band-cta > *{ max-width:var(--col); margin-inline:auto; }
/* Prose stops at a readable line length without moving its left edge. */
.band > h2, .band > h3, .band > p, .band > ol, .band > ul, .band > dl, .band > blockquote,
.band-quiet > h2, .band-quiet > p, .band-cta > h2{ max-width:var(--measure); margin-inline:0; }
.band-cta{ text-align:center; }
.band-cta > *{ margin-inline:auto; }
.page-head > *{ max-width:var(--col); margin-inline:auto; }



/* The demo button. Deliberately the loudest thing in the hero after the title:
   a browser demo is worth more than any amount of copy about how good the game
   is, because the visitor can simply go and find out. */
.cta-play{margin:14px 0 0;}
.btn-play{
  display:inline-block; padding:15px 26px; font-size:0.56rem;
  background:var(--frost); border-color:#9fd6ef; color:#07121a;
}
.btn-play:hover, .btn-play:focus-visible{background:#8fcfe9; border-color:#fff; color:#07121a;}


/* ===========================================================================
   One alignment  (fix, 2026-10-17)
   ---------------------------------------------------------------------------
   Left edges already lined up; the TEXT did not. The sign-up band and the
   footer were centred while every other section was left, so the eye kept
   being thrown as it came down the page.
   Everything reads from the same left edge now. The one exception is the hero
   plate, which is a title card rather than a passage of text - centring there
   is the point of it.
   ======================================================================== */
main, main section, .band, .band-quiet, .band-cta, .band-wide, footer,
.page-head, .page-head > *{ text-align:left; }
.band-cta > *{ margin-inline:0; }
.signup{ justify-content:flex-start; }
.signup-note, .cta-note:not(.hero .cta-note){ text-align:left; }
footer p{ margin-inline:0; }
/* The hero keeps its centring: it is a plate, not prose. */
.hero-plate, .hero-plate *{ text-align:center; }


/* ===================================================== THRONE BANNERS ===
   The geometry lives in index.html, transcribed from the game. Everything
   here is only where they hang and when they arrive.

   They need a bare margin to hang in, and under 1400px there is not one:
   the widest band on the page is 1100px, so a narrower window leaves less
   than about 90px a side, and a banner there would crowd the text rather
   than frame it. So below that they simply do not exist - no half-size
   version to go wrong on a tablet.
   ======================================================================== */
.banners{ display:none; }

@media (min-width: 1120px){
  .banners{
    display:block;
    position:fixed; inset:0; z-index:2;
    /* Fixed IS the whole of "moves with the reader": there is nothing to
       recalculate on scroll, so there is nothing to lag. */
    pointer-events:none;  /* inherited: the music rail shares the right margin */
  }
  .banner-def{ position:absolute; }  /* the symbol holder draws nothing */

  .banner{
    position:absolute; top:0; height:100vh;
    /* 88% of the margin beside the text column, so the cloth is centred in
       the bare strip with air either side and can never reach the words.
       Which dimension binds depends on the window: on a tall screen the
       height does; on a short wide one the width does, and it is this
       number that keeps it off the prose.

       It reads --col, which IS the column (920px, set further down this
       file). It used to say 1100px, a width the page stopped using when
       --col arrived, and that one stale number was the whole bug: the
       margin was measured against a column 180px wider than the real one,
       and the gate above was set to match. On a 1280px-wide display - which
       is what a 1920 monitor at 150% Windows scaling actually gives the
       browser - the banners were switched off entirely and nobody could see
       why. Anything that needs the column must read it from here.

       min() caps the cloth on a wide monitor. Uncapped, a 2560px window
       gives each side an 820px margin and asks for a 721px-wide banner,
       which stops being a hanging banner and becomes a wall. */
    width:min(220px, calc(((100vw - var(--col)) / 2) * 0.88));
  }
  .banner-l{ left:0; }
  .banner-r{ right:0; }
  .banner svg{ display:block; width:100%; height:100%; }

  /* Hanging. They drop in from above the window - which is what a banner
     does - and run back up it when the reader returns to the throne room,
     which is the one place on the page they must not cover. */
  html.js .banner{
    transform:translateY(-104%);
    transition:transform 900ms cubic-bezier(0.22, 0.61, 0.36, 1);
  }
  html.js .banners.in .banner{ transform:none; }
  /* Up again over the footer, which is the one block on the page whose text
     reaches into the margins (full-bleed, aligned on the gutter). Three
     classes beats the two above, so this wins without !important. */
  html.js .banners.in.away .banner{ transform:translateY(-104%); }
  /* The right one a breath behind the left, so they read as two pieces of
     cloth rather than one object in two halves. Not scoped to .in: the
     stagger belongs to the cloth, so it reads the same going up. */
  html.js .banner-r{ transition-delay:120ms; }

  @media (prefers-reduced-motion: reduce){
    html.js .banner{ transition:none; }
  }
}
