/* Reflex Dot · the game's own page
   ---------------------------------------------------------------------------
   Loaded on top of legal.css, which already carries the fonts, the tokens, the
   star field, the trail in the margin, the sections and the footer. Everything
   the three documents established stays; what is here is only what a page about
   a game needs and a policy does not: the opening that breaks the reading
   grid, the score tables, and the three screens.

   Same direction: TRAIL. The dot lands on the section being read. The accent is
   the game's own blue, and it stays rare.
   ------------------------------------------------------------------------- */

:root {
  --opening-measure: 1120px;
  --ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ------------------------------------------------------------- language -- */

/* Both languages live in the HTML; this shows one at a time. Whoever appears
   never has its display redeclared, so each fragment returns to the display it
   already had. Without JavaScript the root carries no data-lang and Portuguese
   is what shows, and the page is complete, just not switchable. */

:root:not([data-lang]) [lang='en'],
:root[data-lang='pt'] [lang='en'] { display: none; }
:root[data-lang='en'] [lang='pt-BR'] { display: none; }

/* The switch is JavaScript's job here, unlike the documents, which do it with
   :target because a store needs a URL per language. On a page with section
   anchors that trick would collapse: any :target would drop the language. So
   without JS there is no switch to show. */
.game .languages { display: none; }
.js .game .languages { display: inline-flex; }

.game .languages {
  padding: 2px;
  border: 1px solid var(--rule);
  border-radius: 999px;
  gap: 0;
}

.game .languages__option {
  appearance: none;
  background: none;
  border: 0;
  margin: 0;
  padding: var(--s-sm) var(--s-lg);
  border-radius: 999px;
  font: inherit;
  font-weight: 600;
  letter-spacing: 0.09em;
  color: var(--light-dim);
  cursor: pointer;
}
.game .languages__option:hover { color: var(--light); background: var(--night-raised); }

.game .languages__option[aria-pressed='true'] {
  color: var(--accent-ink);
  background: var(--light);
}

/* ----------------------------------------------------------- skip link --- */

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 10;
  padding: var(--s-md) var(--s-xl);
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--font-display);
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  border-radius: 0 0 3px 0;
}
.skip-link:focus { left: 0; }

/* ---------------------------------------------------------------- top --- */

.game .top { max-width: var(--opening-measure); }

/* The way back to the studio: the same mark the home's header shows, at the
   same size, and nothing written beside it. Quiet — whoever arrived here came
   for the game — and the pointer brings it up to full. The padding is what
   keeps the target big enough for a thumb now that the name is gone. */
.upstream {
  display: inline-flex;
  align-items: center;
  line-height: 0;
  padding: var(--s-sm) var(--s-xs);
  margin-inline-start: calc(var(--s-xs) * -1);
}

.upstream__mark {
  width: 1.625rem;
  height: auto;
  opacity: 0.78;
  transition: opacity 260ms var(--ease-out);
}
.upstream:hover .upstream__mark,
.upstream:focus-visible .upstream__mark { opacity: 1; }

/* ------------------------------------------------------------- opening -- */

/* The only place on the page where the game is the size it is in your hand.
   Two columns: what the game is on the left, what it looks like on the right,
   and the dot flies away from the text, towards the arc. */

.opening {
  max-width: var(--opening-measure);
  margin-inline: auto;
  padding: clamp(var(--s-3xl), 7vw, var(--s-5xl)) var(--doc-pad) var(--s-4xl);
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  align-items: center;
  column-gap: var(--s-3xl);
}

.opening__label {
  margin: 0 0 var(--s-xl);
  font-family: var(--font-display);
  font-size: var(--t-sm);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--light-dim);
}

/* Wordmark identical to the game's: silver base on top, the two E's filled by
   the accent underneath. Two files, as in Unity. */
/* The wordmark hangs off the same left edge as the label above it and the
   paragraphs below: on this page everything is set from that one margin. */
.opening__title {
  position: relative;
  display: inline-block;
  margin: 0;
  line-height: 0;
}

.wordmark__base {
  position: relative;
  z-index: 1;
  display: block;
  width: clamp(216px, 30vw, 340px);
  height: auto;
}

.wordmark__e {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--accent);
  -webkit-mask-image: url(../assets/reflex-wordmark-e.png);
          mask-image: url(../assets/reflex-wordmark-e.png);
  -webkit-mask-size: 100% 100%;
          mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  mask-mode: alpha;
}

.opening__standfirst {
  margin: var(--s-2xl) 0 0;
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-size: clamp(1.5rem, 1.1rem + 1.9vw, 2.25rem);
  font-weight: 650;
  line-height: 1.06;
  letter-spacing: 0.005em;
  text-transform: uppercase;
  color: var(--light);
}


.opening__lede {
  margin: var(--s-xl) 0 0;
  font-size: var(--t-lg);
  line-height: 1.6;
  color: var(--light-mid);
  max-width: 46ch;
  text-wrap: pretty;
}

.opening__art {
  margin: 0;
  line-height: 0;
}

/* The frame is a phone held upright, sized by height so it never grows into the
   column it shares. The art and the recording stack in it and cross-fade: one
   box, one size, nothing moves on the page when the hand-over happens. */
/* The frame centres itself here, inside a figure that fills its column. Doing
   it the other way round, by centring the figure with an auto inline margin,
   collapsed the whole thing on the iPhone: auto margins take a grid item off
   stretch and size it by its contents, its only content is this frame, and this
   frame asks for a share of the figure. Safari resolves that circle as zero and
   the film came out as a 1px line with the sound still playing. Blink guesses a
   number instead, which is why it only ever showed up on a phone.

   Width named, height made by the ratio. The viewport term keeps a short screen
   from getting a tall frame; svh is the honest unit for it, and the vh line
   above is what browsers that do not know svh read instead. */
.reel {
  position: relative;
  width: min(100%, 286px, 34vh);
  width: min(100%, 286px, 34svh);
  aspect-ratio: 720 / 1560;
  margin-inline: auto;
}

.reel__film,
.reel__art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* A recording of the screen, so it is framed like the three captures further
   down the page: one hairline and nothing else. The game's own night is a
   different night from this page's, which is why this one keeps its edges
   instead of blending away like the artwork. */
.reel__film {
  object-fit: cover;
  border: 1px solid var(--rule);
  border-radius: 14px;
  opacity: 0;
  transition: opacity 700ms var(--ease-out-quint);
}

.reel.is-live .reel__film { opacity: 1; }

/* Key art, not a screenshot. The artwork is light on black, so screen blending
   keys the black out against the night and only the glow survives: no card,
   no border, no visible square. The mask finishes the corners the blend cannot. */
.reel__art {
  object-fit: contain;
  mix-blend-mode: screen;
  /* The fade has to finish before the edge, not at it: ending at 100% leaves a
     faint rectangle where the four edge midpoints still carry alpha. And it has
     to say `circle`: the default shape is an ellipse, which on this tall frame
     would stretch to 124x270 and never reach the top and bottom of the square
     artwork sitting in the middle of it. */
  -webkit-mask-image: radial-gradient(circle closest-side, #000 44%, transparent 94%);
          mask-image: radial-gradient(circle closest-side, #000 44%, transparent 94%);
  transition: opacity 700ms var(--ease-out-quint);
}

.reel.is-live .reel__art { opacity: 0; }

/* The whole frame is the target, so clicking the video does what it looks like
   it does. It only exists once the script is there to answer it. */
.reel__sound {
  position: absolute;
  inset: 0;
  display: none;
  align-items: flex-end;
  justify-content: center;
  padding: var(--s-lg);
  border: 0;
  border-radius: 14px;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
  -webkit-appearance: none;
          appearance: none;
}

.js .reel__sound { display: flex; }

.reel__cue {
  display: inline-flex;
  align-items: center;
  gap: var(--s-sm);
  padding: 0.45em 0.9em;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: rgba(11, 14, 26, 0.72);
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
  font-family: var(--font-display);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  line-height: 1;
  color: var(--light-mid);
  transition: color 200ms ease, border-color 200ms ease;
}

.reel__sound:hover .reel__cue,
.reel__sound:focus-visible .reel__cue { color: var(--light); border-color: var(--light-dim); }

.reel__sound:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.reel__icon { flex: none; fill: currentColor; }

.reel__stroke {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
}

/* Three states, one button, and the word that is showing is the button's
   accessible name: before the hand-over it offers the film, after it offers
   the sound, and once the sound is on it offers to take it back. */
.reel__glyph,
.reel__word { display: none; }

.reel:not(.is-live) .reel__glyph--watch,
.reel.is-live:not(.is-loud) .reel__glyph--unmute,
.reel.is-live.is-loud .reel__glyph--mute { display: inline; }

.reel:not(.is-live) .reel__word--watch,
.reel.is-live:not(.is-loud) .reel__word--unmute,
.reel.is-live.is-loud .reel__word--mute { display: inline; }

/* ---------------------------------------------------------------- stores - */

/* One store exists and the other does not, so only one of them is a button.
   The half that is still coming is plain type: a button that goes nowhere is
   worse than a sentence saying there is nowhere to go yet. */

.stores {
  margin: var(--s-2xl) 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-md) var(--s-xl);
}

/* The note is not a button and must not become one, but it stands beside one:
   it takes the button's height and centres its own text in it. Aligning the two
   line boxes instead would leave the line where it falls in each font, and the
   note and the label are set in different ones. */
.stores__soon {
  display: flex;
  align-items: center;
  min-height: var(--button-height);
  font-size: var(--t-sm);
  color: var(--light-mid);
}

/* ------------------------------------------------------------ sections -- */

/* The document keeps the documents' reading grid (margin column, then measure)
   but stops being centred on its own width: it takes the opening's box, so
   the numerals hang from exactly the same left edge as the wordmark above them
   and the whole page reads off one margin. The space left over falls to the
   right, where the eye does not look for an edge.

   One rule across the top: the opening ends here and the text begins. */
/* A third column, outside the measure: the three screens live there, the way a
   figure lives in a magazine's outer margin. The text sections leave it empty
   and it becomes the page's right-hand air. */
.game .doc {
  max-width: var(--opening-measure);
  grid-template-columns: var(--margin) minmax(0, var(--measure)) minmax(0, 1fr);
}
.game .doc > .section:first-of-type { margin-top: 0; }

/* The rule is inset by the padding rather than sitting on the border, so it
   starts under the wordmark and ends under the art: on the content, not on the
   box. */
.game .doc::before {
  content: '';
  position: absolute;
  top: 0;
  left: var(--doc-pad);
  right: var(--doc-pad);
  height: 1px;
  background: var(--rule);
}

/* --------------------------------------------------------------- ledger -- */

/* The score, as a table, because it is one. Hairlines and tabular figures, the
   way a results page is set: no card, no fill, no zebra. */

.ledger {
  width: 100%;
  /* Wide enough for three columns, narrow enough that the eye crosses from the
     label to the figure without a journey. */
  max-width: 32rem;
  margin: var(--s-xl) 0;
  border-collapse: collapse;
  font-size: var(--t-sm);
  text-align: left;
}

.ledger__caption {
  padding-bottom: var(--s-md);
  font-family: var(--font-display);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--light-dim);
  text-align: left;
}

.ledger th,
.ledger td {
  padding: var(--s-md) var(--s-lg) var(--s-md) 0;
  border-bottom: 1px solid var(--rule);
  vertical-align: baseline;
}
.ledger tbody tr:last-child th,
.ledger tbody tr:last-child td { border-bottom: 0; }

.ledger thead th {
  font-family: var(--font-display);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--light-dim);
}

.ledger tbody th {
  font-family: var(--font-display);
  font-size: var(--t-base);
  font-weight: 650;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--light);
}

.ledger__value {
  font-family: var(--font-display);
  font-size: var(--t-lg);
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  color: var(--light);
  white-space: nowrap;
}
.ledger__value--lit { color: var(--accent); }


/* -------------------------------------------------------------- figures -- */

/* Three numbers that say the whole difficulty curve. They hang at display size
   because they are the argument, not decoration. */

.figures {
  margin: var(--s-xl) 0 var(--s-2xl);
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-xl) var(--s-3xl);
}

.figures__item { min-width: 0; }

.figures dt {
  margin: 0 0 var(--s-xs);
  font-family: var(--font-display);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--light-dim);
}

.figures dd { margin: 0; }

.figures__value {
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-size: clamp(2rem, 1.5rem + 2.2vw, 3rem);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 0.94;
  letter-spacing: -0.01em;
  color: var(--light);
}

.figures__unit { font-size: 0.55em; color: var(--light-dim); }

/* The multiplier strip: same pairs, one size down, because it explains the
   table above it rather than competing with it. */
.figures--tight { margin-bottom: var(--s-xl); gap: var(--s-lg) var(--s-2xl); }
.figures--tight .figures__value { font-size: clamp(1.5rem, 1.2rem + 1.2vw, 2rem); }
.figures__value--lit { color: var(--accent); }

/* ---------------------------------------------------------------- spec --- */

/* No column gap: the two cells' top borders have to meet, or each row reads as
   two broken rules instead of one. The gap comes from the padding instead. */
.spec {
  margin: var(--s-xl) 0 0;
  display: grid;
  grid-template-columns: minmax(9rem, auto) minmax(0, 1fr);
}

.spec dt,
.spec dd {
  margin: 0;
  padding: var(--s-md) 0;
  border-top: 1px solid var(--rule);
}

.spec dt {
  padding-right: var(--s-xl);
  font-family: var(--font-display);
  font-size: var(--t-sm);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--light-dim);
}

.spec dd { color: var(--light); }

/* -------------------------------------------------------------- screen --- */

/* A screen from the game, shown as a screen: one hairline and the game's own
   corner. No bezel, no notch and no shadow: a phone drawn around a screenshot
   says nothing the screenshot did not already say. */

/* The body and the figure share one grid row, so the row is as tall as the
   taller of the two and the figure can never spill onto the section below. */
.section--figure .section__body { grid-column: 2; grid-row: 2; }

.section--figure .screen {
  grid-column: 3;
  grid-row: 2;
  align-self: start;
  margin: 0;
}

.screen img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--rule);
  border-radius: 14px;
}

.screen figcaption {
  margin-top: var(--s-md);
  font-size: var(--t-xs);
  line-height: 1.55;
  color: var(--light-dim);
  text-wrap: pretty;
}

/* ---------------------------------------------------------------- nick --- */

/* A drawn nickname is a sample of machine output, not a name. */
.nick {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  color: var(--light);
  white-space: nowrap;
}

/* -------------------------------------------------------------- footer --- */

.game .footer__inner {
  max-width: var(--opening-measure);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s-2xl);
  align-items: start;
}

@media (min-width: 720px) {
  .game .footer__inner { grid-template-columns: auto minmax(0, 1fr); gap: var(--s-3xl); }
  .game .footer__entity-block { justify-self: end; text-align: right; }
}

.footer__docs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-sm) var(--s-xl);
  align-items: baseline;
}

.footer__label {
  width: 100%;
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--t-sm);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--light-dim);
}

.footer__docs a { color: var(--light-mid); }
.footer__docs a:hover { color: var(--light); }

.footer__entity-block {
  display: flex;
  flex-direction: column;
  gap: var(--s-xs);
  align-items: flex-start;
}
@media (min-width: 720px) {
  .game .footer__entity-block { align-items: flex-end; }
}

/* ---------------------------------------------------------- responsive -- */

/* Below the fold of a laptop the two columns of the opening stop being two:
   the art goes first, because on a phone the picture is what says what this is
   before a single word is read. */
@media (max-width: 860px) {
  .opening {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--s-2xl);
  }

  /* Stacked, the figure comes first and spans the column; the frame inside it
     is what centres, and the wordmark and the paragraphs below keep hanging off
     the left margin. No max-width and no auto margin here: both would size this
     figure by its contents, and its contents are sized from it. */
  .opening__art { order: -1; }

  /* legal.css has already turned the sections into blocks here; the figure
     stops being a margin note and becomes part of the flow. */
  .game .doc { grid-template-columns: var(--margin) minmax(0, var(--measure)); }
  .section--figure .screen { margin-top: var(--s-2xl); max-width: 300px; }
}

@media (max-width: 560px) {
  .opening { padding-inline: var(--s-lg); }

  .game .top { padding-inline: var(--s-lg); }

  .figures { gap: var(--s-lg) var(--s-2xl); }
  .figures--tight { gap: var(--s-md) var(--s-xl); }
}

/* ------------------------------------------------------------- motion --- */

/* One entrance, staggered, and nothing else moves on load. The trail takes over
   from there. */
@media (prefers-reduced-motion: no-preference) {
  .js .opening__label,
  .js .opening__title,
  .js .opening__standfirst,
  .js .opening__lede,
  .js .stores { animation: rise 640ms var(--ease-out-quint) backwards; }

  .js .opening__label      { animation-delay: 60ms; }
  .js .opening__title      { animation-delay: 120ms; }
  .js .opening__standfirst { animation-delay: 190ms; }
  .js .opening__lede       { animation-delay: 260ms; }
  .js .stores              { animation-delay: 330ms; }

  /* The art arrives the way the ball does: already moving. */
  .js .reel__art { animation: arrive 900ms var(--ease-out-quint) backwards; }
}

@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

@keyframes arrive {
  from { opacity: 0; transform: translate3d(-3%, 3%, 0) scale(0.94); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  /* The hand-over still happens on request; it just stops being a fade. */
  .reel__film,
  .reel__art { transition: none; }
}

/* --------------------------------------------------------------- print -- */

@media print {
  .opening {
    display: block;
    padding: 0;
    max-width: none;
  }
  .opening__art { display: none; }
  .wordmark__base { width: 200px; filter: invert(1) contrast(1.4); }
  .wordmark__e { background: #111; }
  .opening__standfirst,
  .opening__lede,
  .ledger tbody th,
  .ledger__value,
  .figures__value,
  .spec dd { color: #111; }
  .button--primary { background: none; border: 1px solid #666; }
  .stores__soon { color: #111; }
  .screen { break-inside: avoid; }
  .screen img { width: 150px; }
  .upstream, .skip-link { display: none; }
  .ledger th, .ledger td, .spec dt, .spec dd { border-color: #bbb; }
}
