/* DEATH STEEL site, 5th draft: one take.
   A single WebGL canvas fills the screen for the whole page; the scroll is the camera's time.
   This sheet styles only what sits on top of it: the words of each stretch, and the chrome.
   Archivo at three widths: 62 = trailer titles, 100 = text, 125 = next to the logo. */

/* All three families are served from this site (tools/make_fonts.py): nothing is fetched from anyone else. */
@font-face {
  font-family: "Archivo";
  src: url("assets/fonts/Archivo-VF.woff2") format("woff2");
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
}
/* The game's own UI faces, for the cards and the parry prompt. */
@font-face {
  font-family: "Cormorant Garamond";
  src: url("assets/fonts/CormorantGaramond-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Cormorant Garamond";
  src: url("assets/fonts/CormorantGaramond-500-italic.woff2") format("woff2");
  font-weight: 500;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Lato";
  src: url("assets/fonts/Lato-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --black: #000;
  --night: #0f1517;
  --blood: #992a28;
  --haze: #9eabac;
  --steel: #f7f7f7;
  --spark: #ffd28a;            /* hot metal: the moment to press */
  --gutter: clamp(20px, 5vw, 80px);
  --out: cubic-bezier(0.16, 1, 0.3, 1);
  --bars: 0px;                 /* the height a phone browser's bars cover while they show (see below) */
}
/* The stage is as tall as the screen with the browser's bars away. While they show, they cover
   this much of its lower edge: words set against that edge stand this much higher. */
@supports (height: 100svh) { :root { --bars: calc(100lvh - 100svh); } }

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }
html.lenis, html.lenis body { height: auto; }
html.is-locked { overflow: hidden; }

body {
  margin: 0;
  background: var(--black);
  color: var(--steel);
  font-family: "Archivo", "Segoe UI", system-ui, sans-serif;
  font-stretch: 100%;
  font-weight: 400;
  font-size: clamp(1rem, 0.94rem + 0.3vw, 1.1875rem);
  line-height: 1.55;
  overflow-x: hidden;
}

img, video, canvas { display: block; max-width: 100%; }
p { margin: 0; }
a { color: inherit; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
[hidden] { display: none !important; }
:focus-visible { outline: 3px solid var(--steel); outline-offset: 4px; }

/* ---------- Shared pieces ---------- */

.title {
  margin: 0;
  font-stretch: 62%;
  font-weight: 900;
  font-size: clamp(3.5rem, 11.5vw, 11.5rem);
  line-height: 0.84;
  letter-spacing: -0.005em;
  text-transform: uppercase;
}
.title--ghost { color: rgb(247 247 247 / 0.6); }
/* Titles rise from behind their baseline, the way the trailer's cards do. */
.title .line { display: block; overflow: hidden; padding-top: 0.06em; margin-top: -0.06em; }
.title .line > span { display: block; transform: translateY(104%); transition: transform 0.8s var(--out); }
.title .line:nth-child(2) > span { transition-delay: 0.09s; }
.panel.is-on .title .line > span { transform: none; }

.lead { max-width: 24em; font-size: clamp(1.0625rem, 1rem + 0.5vw, 1.5rem); line-height: 1.35; }
.note { max-width: 34em; font-size: 0.875rem; line-height: 1.45; color: var(--haze); }

/* Paragraphs arrive a word at a time, each rising from behind its own line. */
.word { display: inline-block; overflow: hidden; vertical-align: top; padding-bottom: 0.16em; margin-bottom: -0.16em; }
.word > span { display: inline-block; transform: translateY(115%); transition: transform 0.7s var(--out); transition-delay: calc(0.2s + var(--i) * 0.024s); }
.panel.is-on .word > span { transform: none; }

.btn {
  position: relative;
  isolation: isolate;
  display: inline-block;
  padding: 1.05em 1.5em 1em;
  background: var(--steel);
  color: var(--night);
  font-stretch: 125%;
  font-weight: 800;
  font-size: 0.875rem;
  letter-spacing: 0.02em;
  line-height: 1;
  text-transform: uppercase;
  text-decoration: none;
  transition: color 0.25s;
}
/* Hovering fills the button with the key art's red, from the bottom up. */
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--blood);
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform 0.35s var(--out);
}
.btn:hover { color: var(--steel); }
.btn:hover::before { transform: scaleY(1); }
.btn--small { font-size: 0.6875rem; padding: 0.95em 1.3em 0.9em; }
/* The one button a screen is asking for: larger, and rings go out from it until it is used. */
.btn--loud {
  font-size: 1.0625rem;
  padding: 1.25em 1.7em 1.2em;
  animation: rings 1.8s var(--out) infinite, swell 1.8s ease-in-out infinite;
}
@keyframes rings {
  0% { box-shadow: 0 0 0 0 rgb(247 247 247 / 0.7), 0 0 0 0 rgb(247 247 247 / 0); }
  50% { box-shadow: 0 0 0 1.25rem rgb(247 247 247 / 0), 0 0 0 0 rgb(247 247 247 / 0.7); }
  100% { box-shadow: 0 0 0 1.25rem rgb(247 247 247 / 0), 0 0 0 1.25rem rgb(247 247 247 / 0); }
}
@keyframes swell { 50% { scale: 1.04; } }

.link { text-decoration: underline; text-underline-offset: 0.25em; text-decoration-thickness: 1px; }
.link:hover { text-decoration-thickness: 2px; }
.actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1.25rem 2rem; }

/* A key, drawn the way the game's own key hints are. */
kbd {
  display: inline-block;
  padding: 0.32em 0.6em 0.26em;
  border: 1px solid currentColor;
  font: inherit;
  font-stretch: 100%;
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1;
  text-transform: none;
}

/* ---------- The gate ---------- */

/* The canvas behind is dark and carries the embers; this is only the logo and the choice. */
.gate {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 2rem;
  transition: opacity 0.9s ease-out, visibility 0s 0.9s;
}
.gate__logo { width: clamp(12rem, 24vw, 22rem); height: auto; opacity: 0; transition: opacity 0.7s ease-out; }
.gate.is-formed .gate__logo { opacity: 1; }
.gate__line { width: 12rem; height: 2px; background: rgb(247 247 247 / 0.2); transition: opacity 0.4s; }
.gate__line span { display: block; height: 100%; background: var(--steel); transform-origin: left; transform: scaleX(var(--loaded, 0)); transition: transform 0.4s ease-out; }
.gate__choice { display: grid; justify-items: center; gap: 1.5rem; opacity: 0; visibility: hidden; transform: translateY(10px); transition: opacity 0.6s, transform 0.6s var(--out); }
.gate.is-ready .gate__line { opacity: 0; }
.gate.is-ready .gate__choice { opacity: 1; visibility: visible; transform: none; }
/* Entered: the gate fades away and takes no more presses. Its buttons are made visible by their
   own rule above, so they have to be told to go as well, or they would keep catching taps unseen. */
.is-in .gate { opacity: 0; visibility: hidden; pointer-events: none; }
.is-in .gate .gate__choice { visibility: hidden; transition: visibility 0s 0.9s; }

/* ---------- Chrome: bar, chapter index, sound ---------- */

.bar {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem var(--gutter);
  pointer-events: none;
}
.bar > * { opacity: 0; transform: translateY(-0.5rem); transition: opacity 0.4s, transform 0.4s var(--out); }
.bar__logo img { height: 1.5rem; width: auto; }
.bar.is-on > * { opacity: 1; transform: none; pointer-events: auto; }

.index {
  position: fixed;
  z-index: 20;
  right: var(--gutter);
  top: 50%;
  transform: translateY(-50%);
  display: grid;
  justify-items: end;
  gap: 0.55rem;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.6s, visibility 0s 0.6s;
}
.index.is-on { opacity: 1; visibility: visible; transition: opacity 0.6s; }
.index button {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.75rem;
  line-height: 1.2;
  color: rgb(247 247 247 / 0.5);
  transition: color 0.2s;
}
.index button::after { content: ""; width: 1rem; height: 1px; background: currentColor; transition: width 0.3s var(--out); }
.index button:hover { color: var(--steel); }
.index button.is-here { color: var(--steel); }
.index button.is-here::after { width: 2.25rem; height: 2px; }

.sound {
  position: fixed;
  z-index: 21;
  right: var(--gutter);
  bottom: 1rem;
  padding: 0.5em 0.9em;
  font-size: 0.75rem;
  line-height: 1.2;
  background: rgb(0 0 0 / 0.55);
  border: 1px solid rgb(247 247 247 / 0.35);
  /* Not at the gate: the gate itself asks about sound. */
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.6s, visibility 0s 0.6s;
}
.is-in .sound { opacity: 1; visibility: visible; transition: opacity 0.6s; }
.sound[aria-pressed="true"] { background: var(--steel); color: var(--night); border-color: var(--steel); }

/* ---------- The take ---------- */

.take { position: relative; height: calc((var(--pages, 15) + 1) * 100vh); }
/* A finger scrolls the page up and down from anywhere on the stage (and may pinch to zoom); sideways it slides the row of cards. */
.stage { position: sticky; top: 0; height: 100vh; overflow: hidden; background: var(--black); touch-action: pan-y pinch-zoom; -webkit-tap-highlight-color: transparent; }
.world { position: absolute; inset: 0; width: 100%; height: 100%; }

/* A panel is the words for one stretch of the take. It lets clicks through to the canvas
   everywhere except on its own buttons and links. */
.panel {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  gap: clamp(1.25rem, 2.5vw, 2.25rem);
  padding: clamp(4.5rem, 10vh, 6.5rem) var(--gutter);
  pointer-events: none;
  isolation: isolate;          /* keeps each panel's shade above the canvas */
  --lean-x: calc(var(--px, 0) * -14px);       /* the words lean a little away from the pointer */
  --lean-y: calc(var(--py, 0) * -9px);
  translate: var(--lean-x) var(--lean-y);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.5s, visibility 0s 0.5s;
}
.panel.is-on { opacity: 1; visibility: visible; transition: opacity 0.5s; }
.panel.is-on :is(a, button) { pointer-events: auto; }
.panel > .lead, .panel > .note, .panel > .actions { opacity: 0; transform: translateY(14px); transition: opacity 0.7s 0.25s, transform 0.7s 0.25s var(--out); }
.panel.is-on > .lead, .panel.is-on > .note, .panel.is-on > .actions { opacity: 1; transform: none; }
.panel > .actions { transition-delay: 0.38s; }

/* A shade behind the words reaches the screen's edges, so it stays put while the words lean. */
.panel::before, .rail::before { translate: calc(var(--lean-x) * -1) calc(var(--lean-y) * -1); }
/* Words over footage or cards get a shade behind them. */
.panel--duel::before, .panel--cards::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(to right, rgb(0 0 0 / 0.8), rgb(0 0 0 / 0.45) 40%, transparent 68%);
}

.panel--standoff .logo { margin: 0; overflow: hidden; }
.panel--standoff .logo img { width: clamp(15rem, 34vw, 38rem); height: auto; transform: translateY(104%); transition: transform 1s 0.5s var(--out); }
.is-in .panel--standoff.is-on .logo img { transform: none; }
.panel--standoff > .lead { transition-delay: 0.9s; }
.panel--standoff > .actions { transition-delay: 1.05s; }
.panel--standoff .lead { max-width: 17em; }

.panel--walk { justify-content: flex-end; padding-bottom: calc(clamp(4.5rem, 10vh, 6rem) + var(--bars)); }

/* ---------- Parry everything ---------- */

.panel--parry { justify-content: flex-start; padding-bottom: 0; }
.panel--parry .title { opacity: var(--title, 1); }
.rail {
  position: absolute;
  inset: auto 0 0 0;
  isolation: isolate;
  padding: 22vh var(--gutter) calc(clamp(3.5rem, 6vw, 4rem) + var(--bars));
}
.rail::before { content: ""; position: absolute; inset: 0; z-index: -1; background: linear-gradient(to bottom, transparent, rgb(0 0 0 / 0.72) 62%); }
.rail__text { margin-bottom: clamp(1.25rem, 2.5vw, 2rem); max-width: 24em; font-size: clamp(1rem, 0.95rem + 0.4vw, 1.3125rem); line-height: 1.4; }
.rail__line { position: relative; height: 2px; background: rgb(247 247 247 / 0.28); }
.rail__head { position: absolute; inset: 0 auto 0 0; width: 100%; background: var(--steel); transform-origin: left center; transform: scaleX(var(--p, 0)); }
/* A diamond is one hit. It is empty until that hit has been stopped. */
.rail__mark, .defend__pips span { display: block; width: 14px; height: 14px; transform: rotate(45deg); background: var(--black); border: 2px solid var(--steel); }
.rail__mark { position: absolute; left: var(--at); top: 50%; margin: -7px 0 0 -7px; z-index: 1; }
.rail__mark.is-hit, .defend__pips span.is-hit { background: var(--steel); }
.rail__mark::after, .defend__pips span::after { content: ""; position: absolute; inset: -2px; border: 2px solid var(--steel); opacity: 0; }
.rail__mark.is-hit::after, .defend__pips span.is-hit::after { animation: burst 0.6s var(--out); }
@keyframes burst { from { opacity: 0.9; transform: scale(1); } to { opacity: 0; transform: scale(4.5); } }
.rail__legend { display: flex; justify-content: space-between; gap: 1rem; margin-top: 0.9rem; font-size: 0.875rem; line-height: 1.2; color: rgb(247 247 247 / 0.8); }
.rail__count { font-variant-numeric: tabular-nums; text-align: right; }

/* ---------- Now you defend ---------- */

.panel--defend {
  --ring: clamp(10rem, 36vh, 23rem);     /* the prompt's size */
  --beat: 2.4s;                          /* one rehearsal of the parry, while the prompt waits */
  --lean-x: 0px;                         /* no lean: the prompt must stay exactly on the clip's point of impact */
  --lean-y: 0px;
}
/* The room goes dark around the spot where the blades will meet. */
.panel--defend::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(circle at var(--cx, 50%) var(--cy, 50%), transparent calc(var(--ring) * 0.5), rgb(0 0 0 / 0.68) calc(var(--ring) * 1.5)),
    linear-gradient(to right, rgb(0 0 0 / 0.5), transparent 50%);
  transition: opacity 0.3s;
}
/* The words keep to the left of the prompt: no wider, and no larger, than the room it leaves them. */
.defend__words {
  --room: calc(var(--cx, 50vw) - var(--ring) / 2 - var(--gutter) - 1.5rem);
  display: grid;
  justify-items: start;
  gap: clamp(1.25rem, 2.5vw, 2rem);
  max-width: var(--room);
  transition: opacity 0.25s;
}
.defend__words .title { font-size: min(clamp(3.5rem, 9vw, 10rem), var(--room) / 3.4); }
/* Once a round has been played the result takes the title's place (the title would sit on the game's own PARRY!). */
.panel--defend:is(.is-cleared, .is-failed) .title { display: none; }

/* The prompt: a hairline ring on the spot where the blades will meet, drawn the way the game
   draws its own timing rings. While it waits it rehearses the parry, once every beat: a ring
   closes on it, lands, and the key dips. A beat begins as that ring lands. */
.prompt {
  position: absolute;
  left: var(--cx, 50%);
  top: var(--cy, 50%);
  width: var(--ring);
  height: var(--ring);
  margin: calc(var(--ring) / -2) 0 0 calc(var(--ring) / -2);
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: var(--steel);
}
/* The ring is drawn 100 units out of the 110 from the centre to the box's edge. */
.prompt::before, .prompt__comet { position: absolute; inset: 4.55%; border-radius: 50%; }
/* A shade inside the ring, so the key reads over the footage. */
.prompt::before { content: ""; background: radial-gradient(circle, rgb(0 0 0 / 0.42), rgb(0 0 0 / 0.22)); transition: opacity 0.3s; }
/* A light that runs round the ring: a bright head and a fading tail, a little wider than the ring's line. */
.prompt__comet {
  margin: -2px;
  background: conic-gradient(transparent 235deg, color-mix(in srgb, currentColor 22%, transparent) 320deg, currentColor 353deg, transparent);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 4.5px), #000 calc(100% - 4px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 4.5px), #000 calc(100% - 4px));
  animation: turn 7s linear infinite;
}
@keyframes turn { to { rotate: 360deg; } }

.prompt__rings { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; filter: drop-shadow(0 0 2px rgb(0 0 0 / 0.75)); }
.prompt__rings circle { fill: none; stroke: currentColor; vector-effect: non-scaling-stroke; transform-box: fill-box; transform-origin: center; }
.prompt__target { stroke-width: 1.5; stroke-opacity: 0.75; animation: land var(--beat) var(--out) infinite; }
.prompt__finials { fill: currentColor; }                  /* a blade's point at 12, 3, 6 and 9 */
.prompt__call { stroke-width: 1; opacity: 0; animation: call var(--beat) linear infinite; }
.prompt__echo { stroke-width: 1; opacity: 0; animation: echo var(--beat) var(--out) infinite; }
.prompt__approach { stroke-width: 2; opacity: 0; }        /* the timing rings: placed by script during a round */
@keyframes call { 0%, 50% { scale: 1.8; opacity: 0; } 62% { opacity: 0.85; } 100% { scale: 1; opacity: 0.85; } }
@keyframes land { 0% { stroke-width: 4; stroke-opacity: 1; } 30%, 100% { stroke-width: 1.5; stroke-opacity: 0.75; } }
@keyframes echo { 0% { scale: 1; opacity: 0.7; } 40%, 100% { scale: 1.28; opacity: 0; } }

.prompt__core { position: relative; display: grid; justify-items: center; gap: 0.75rem; font-family: "Cormorant Garamond", Georgia, serif; transition: translate 0.35s var(--out); }
/* The key, as the game draws its key hints: a dark cap with a hairline edge. Long, like the bar it stands for. */
.prompt__key {
  min-width: 5.4em;
  padding: 0.42em 1em 0.4em;
  border-color: rgb(247 247 247 / 0.85);
  border-radius: 3px;
  background: rgb(8 10 12 / 0.62);
  font-size: clamp(1.125rem, 2.6vh, 1.5rem);
  letter-spacing: 0.03em;
  text-align: center;
  animation: tap var(--beat) var(--out) infinite;
}
@keyframes tap {
  0%, 100% { translate: 0 0.14em; background-color: rgb(247 247 247 / 0.26); }
  14%, 96% { translate: 0 0; background-color: rgb(8 10 12 / 0.62); }
}
.prompt__label { margin-right: -0.24em; font-weight: 600; font-size: clamp(0.8125rem, 1.75vh, 1rem); letter-spacing: 0.24em; line-height: 1; text-transform: uppercase; text-shadow: 0 0 0.6em rgb(0 0 0 / 0.9); }

/* One diamond per hit, above the ring. */
.defend__pips { position: absolute; left: 50%; bottom: calc(100% + 0.6rem); translate: -50% 0; display: flex; gap: 1.1rem; opacity: 0; transition: opacity 0.25s; }
.defend__pips span { position: relative; width: 11px; height: 11px; border-width: 1.5px; }
.defend__pips span::after { inset: -1.5px; border-width: 1.5px; }

/* The rehearsal rests while the panel is away. */
.panel--defend:not(.is-on) .prompt * { animation-play-state: paused; }
/* During a round there is nothing on screen but the fight, the ring, and the key under it. */
.panel--defend.is-running::before, .panel--defend.is-running .defend__words, .panel--defend.is-running .prompt::before { opacity: 0; }
.panel--defend.is-running :is(.prompt__comet, .prompt__call, .prompt__echo) { display: none; }
.panel--defend.is-running :is(.prompt__target, .prompt__key) { animation: none; }
.panel--defend.is-running .prompt__core { translate: 0 calc(var(--ring) * 0.68); }
.panel--defend:is(.is-running, .is-cleared) .defend__pips { opacity: 1; }
/* The moment to press: the ring turns to hot metal and the key fills with it. */
.panel--defend.is-hot .prompt { color: var(--spark); }
.panel--defend.is-hot .prompt__target { stroke-width: 3.5; stroke-opacity: 1; }
.panel--defend.is-hot .prompt__rings { filter: drop-shadow(0 0 0.5rem rgb(255 210 138 / 0.6)); }
.panel--defend.is-hot .prompt__key { border-color: var(--spark); background: var(--spark); color: var(--night); }
.panel--defend .prompt__key.is-pressed { animation: pressed 0.2s var(--out); }
@keyframes pressed { from { scale: 0.9; } }
/* A round lost: the ring shakes its head. */
.panel--defend.is-failed .prompt__rings { animation: refuse 0.4s var(--out); }
@keyframes refuse { 0% { translate: -6px 0; } 25% { translate: 5px 0; } 50% { translate: -3px 0; } 75% { translate: 2px 0; } 100% { translate: 0 0; } }
.panel--defend.is-cleared :is(.prompt__target, .prompt__finials, .prompt__comet) { color: var(--spark); }

/* ---------- Where the film is a band ---------- */

/* On a screen narrower than the film (a phone, a tablet held upright) the film is a band across
   the middle. The stage is then marked is-banded and carries the band's top and height. The
   words keep clear of the band: a title stands on its top edge, the rest goes under it. */
.is-banded :is(.panel--duel, .panel--parry, .panel--defend) {
  display: grid;
  grid-template: var(--band-top) var(--band-height) auto auto / minmax(0, 1fr);
  place-content: start stretch;
  justify-items: start;
  gap: 0;
  padding-block: 0;
}
.is-banded :is(.panel--duel, .panel--parry, .panel--defend) .title {
  grid-row: 1;
  align-self: end;
  margin-bottom: 0.8rem;
  font-size: min(clamp(3rem, 15vw, 11.5rem), (var(--band-top) - 5rem) / 1.7);       /* its two lines fit between the top bar and the band */
}
.is-banded .panel--duel > .lead, .is-banded .defend__msg { grid-row: 3; margin-top: 1.1rem; }
.is-banded .panel--duel > .actions, .is-banded .defend__wish { grid-row: 4; margin-top: 1.1rem; }
.is-banded .panel--duel::before { content: none; }               /* nothing lies over the film here */
.is-banded .defend__words { display: contents; }
.is-banded .panel--defend { --ring: min(clamp(10rem, 36vh, 23rem), var(--band-height) * 0.56); }
.is-banded .panel--defend::before { background: radial-gradient(circle at var(--cx, 50%) var(--cy, 50%), transparent calc(var(--ring) * 0.5), rgb(0 0 0 / 0.6) calc(var(--ring) * 1.5)); }
.is-banded .panel--defend :is(.title, .defend__msg) { transition: opacity 0.25s; }
.is-banded .panel--defend.is-running :is(.title, .defend__msg) { opacity: 0; }

/* ---------- Card time ---------- */

.panel--cards > :not(.title) { max-width: min(30vw, 26rem); }
.panel--cards .title { font-size: clamp(3rem, 6.2vw, 7.5rem); white-space: nowrap; }
.panel--cards .lead { font-size: clamp(1rem, 0.95rem + 0.3vw, 1.25rem); }
.cards__hint { font-size: 0.875rem; color: rgb(247 247 247 / 0.8); }
/* On a narrow screen the hand is a row of cards to slide through (the panel is marked is-row):
   the words stay at the top, the hint goes under the row. */
.panel--cards.is-row { justify-content: flex-start; padding-bottom: calc(4.25rem + var(--bars)); }
.panel--cards.is-row::before { background: linear-gradient(to bottom, rgb(0 0 0 / 0.8), transparent 50%); }
.panel--cards.is-row > :not(.title) { max-width: none; }
.panel--cards.is-row .note { display: none; }
.panel--cards.is-row .actions { flex-direction: column; align-self: center; justify-content: flex-end; gap: 0.8rem; min-height: 3.6rem; margin-top: auto; text-align: center; }
/* One diamond per card of the row; the card in front has its diamond filled. */
.cards__pips { display: none; gap: 0.75rem; }
.panel--cards.is-row .cards__pips { display: flex; }
.cards__pips span { display: block; width: 7px; height: 7px; rotate: 45deg; border: 1px solid rgb(247 247 247 / 0.75); transition: background-color 0.2s; }
.cards__pips span.is-front { background: var(--steel); }

/* ---------- The rival ---------- */

.panel--rival { justify-content: flex-end; padding-bottom: calc(clamp(4rem, 9vh, 6rem) + var(--bars)); }
.panel--rival::before { content: ""; position: absolute; inset: 0; z-index: -1; background: linear-gradient(to top, rgb(0 0 0 / 0.8), transparent 55%); }
.rival__logo { width: clamp(13rem, 28vw, 28rem); height: auto; }

.cue {
  position: absolute;
  left: 50%;
  bottom: calc(1.5rem + var(--bars));
  transform: translateX(-50%);
  padding-bottom: 2.25rem;
  font-size: 0.8125rem;
  color: rgb(247 247 247 / 0.7);
  opacity: 0;
  transition: opacity 0.5s;
}
.cue.is-on { opacity: 1; }
.cue::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 1px;
  height: 1.75rem;
  background: var(--steel);
  transform-origin: top;
  animation: cue 1.8s var(--out) infinite;
}
@keyframes cue { 0% { transform: scaleY(0); } 60% { transform: scaleY(1); opacity: 1; } 100% { transform: scaleY(1); opacity: 0; } }

/* ---------- Without WebGL ---------- */

.plain { display: none; }
.no-gl :is(.take, .gate, .index, .sound, .bar) { display: none; }
.no-gl .plain { display: grid; justify-items: start; gap: 1.5rem; padding: var(--gutter); }
.plain__logo { width: clamp(13rem, 30vw, 26rem); height: auto; }
.plain video { width: 100%; height: auto; aspect-ratio: 16 / 9; }

/* ---------- Footer ---------- */

.foot {
  position: relative;
  display: grid;
  gap: 1.5rem;
  padding: 0 var(--gutter) 4.5rem;
  background: var(--black);
  font-size: 0.9375rem;
  color: var(--haze);
}
.foot a { color: var(--steel); text-underline-offset: 0.25em; text-decoration-thickness: 1px; }
.foot__nav { display: flex; flex-wrap: wrap; gap: 0.5rem 2rem; }
.foot__legal { font-size: 0.8125rem; max-width: 60em; }

/* Where else the game lives: one row per place, its name in the trailer's title face.
   The rows run from edge to edge of the screen, and fill with the key art's red under the pointer. */
.links { grid-column: 1 / -1; margin: 0 calc(var(--gutter) * -1) clamp(1rem, 3vw, 2.5rem); border-bottom: 1px solid rgb(247 247 247 / 0.16); }
.links__row {
  position: relative;
  isolation: isolate;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.25rem 1.5rem;
  padding: clamp(0.9rem, 1.6vw, 1.5rem) var(--gutter) clamp(0.7rem, 1.3vw, 1.2rem);
  border-top: 1px solid rgb(247 247 247 / 0.16);
  text-decoration: none;
}
.links__row::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--blood);
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform 0.35s var(--out);
}
.links__row:is(:hover, :focus-visible)::before { transform: scaleY(1); }
.links__name { font-stretch: 62%; font-weight: 900; font-size: clamp(2.75rem, 6vw, 5.5rem); line-height: 0.9; letter-spacing: -0.005em; text-transform: uppercase; transition: translate 0.35s var(--out); }
.links__what { font-size: clamp(0.9375rem, 0.88rem + 0.3vw, 1.125rem); color: var(--haze); transition: color 0.25s; }
.links__row:is(:hover, :focus-visible) .links__name { translate: 0.18em 0; }
.links__row:is(:hover, :focus-visible) .links__what { color: var(--steel); }
.links__row:focus-visible { outline-offset: -3px; }
/* On a wide screen the rows stand two abreast, with a rule between the columns. */
@media (min-width: 900px) {
  .links { display: grid; grid-template-columns: 1fr 1fr; }
  .links__row:nth-child(even) { border-left: 1px solid rgb(247 247 247 / 0.16); }
}

/* ---------- Trailer ---------- */

.film {
  width: min(100vw - 2 * var(--gutter), (100vh - 9rem) * 16 / 9);
  max-width: none;
  max-height: none;
  padding: 0;
  border: 0;
  background: var(--black);
  color: var(--steel);
  overflow: visible;
}
.film::backdrop { background: rgb(0 0 0 / 0.92); }
.film video { width: 100%; height: auto; aspect-ratio: 16 / 9; }
.film__close { position: absolute; right: 0; bottom: calc(100% + 0.75rem); font-size: 0.875rem; text-decoration: underline; text-underline-offset: 0.25em; }
/* Says how far a download has got, where the trailer must be fetched whole before it can play. */
.film__note { position: absolute; left: 0; top: calc(100% + 0.75rem); font-size: 0.875rem; color: var(--haze); }

@media (min-width: 900px) {
  .foot { grid-template-columns: 1fr auto; }
  .foot__legal { grid-column: 1 / -1; }
}

/* ---------- Narrow screens ---------- */

@media (max-width: 700px) {
  /* The chapter index is here to be read, not pressed: its names go, its marks stay, at the screen's edge. */
  .index { right: 7px; gap: 0.6rem; pointer-events: none; }
  .index button { gap: 0; font-size: 0; }
  .index button::after { width: 0.4rem; }
  .index button.is-here::after { width: 0.9rem; }
  .gate__logo { width: 14rem; }
  .panel--standoff { justify-content: flex-end; padding-bottom: calc(7rem + var(--bars)); }
  .panel--standoff::before { content: ""; position: absolute; inset: 0; z-index: -1; background: linear-gradient(to top, rgb(0 0 0 / 0.88) 18%, transparent 62%); }
  .prompt__key { font-size: 1rem; }
  .prompt__label { font-size: 0.75rem; }
  .prompt__core { gap: 0.5rem; }
  .rail__legend { font-size: 0.8125rem; }
  .links__row { flex-direction: column; }
}
@media (max-width: 700px) and (max-height: 760px) {
  .is-banded .panel--duel .note { display: none; }       /* a short phone has no room for it under the band */
}

/* ---------- Short screens (a phone held sideways) ---------- */

@media (max-height: 520px) {
  .panel--cards .note { display: none; }
}
/* On a small screen the walk's words stand on the burning ground (and, sideways, on the title in the field): a shade keeps them readable. */
@media (max-width: 700px), (max-height: 520px) {
  .panel--walk::before { content: ""; position: absolute; inset: 0; z-index: -1; background: linear-gradient(to top, rgb(0 0 0 / 0.72), transparent 42%); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
  .title .line > span, .panel--standoff .logo img, .word > span { transform: none; }
}
