/* ============================================================
   CAPTAIN'S CALL — playcaptainscall.com
   ============================================================
   Structure borrowed from pyroplay.com, palette taken from the game.

   The borrowed part is the *shape*: separation by tone rather than by
   borders, nested rounded islands, one accent used sparingly, motion tokens
   declared once at the top. That system is already proven on a phone, and
   re-deriving it would have been waste.

   The palette is not borrowed. PyroPlay is fire orange; this is the game's
   own broadcast navy and gold, arriving in tokens.css straight from
   src/config/tokens.ts. Nothing below states a colour — everything states a
   token, so a change to the game's palette reaches this site by re-running
   one script.
   ============================================================ */

/* ============================================================
   1 · THEME — roles, mapped onto the game's raw palette
   ============================================================
   tokens.css says what #d4af37 is called. This says what it is for. Keeping
   the two apart is what lets the generated file be overwritten without ever
   touching a design decision.
   ============================================================ */
:root {
  /* Surfaces, as a tonal ladder. Each step is lighter than the last, which is
     what separates one island from another with no line between them. */
  --ground: var(--cc-navy-950);
  --surface: var(--cc-navy-900);
  --surface-high: var(--cc-navy-800);
  --surface-higher: var(--cc-navy-700);

  --fill: rgba(246, 248, 252, 0.05);
  --fill-hover: rgba(246, 248, 252, 0.09);

  --on-surface: var(--cc-ink-050);
  --on-surface-variant: var(--cc-ink-200);
  --on-surface-muted: var(--cc-ink-400);
  --on-surface-faint: var(--cc-ink-600);

  /* Gold is value. CTA is money moved. They are close on purpose and used for
     different things on purpose — see the note in the game's tokens.ts. */
  --accent: var(--cc-gold-500);
  --accent-bright: var(--cc-gold-300);
  --accent-soft: var(--cc-gold-400);
  --cta: var(--cc-cta-500);
  --cta-hover: var(--cc-cta-400);
  --on-cta: var(--cc-navy-950);

  --win: var(--cc-win-500);
  --lose: var(--cc-lose-500);
  --team-blue: var(--cc-team-blue-500);
  --team-red: var(--cc-team-red-500);

  --accent-rgb: 212, 175, 55;
  --ink-rgb: 246, 248, 252;

  /* Shape */
  --r-xs: 6px;
  --r-sm: 10px;
  --r-md: 16px;
  --r-card: 22px;
  --r-panel: 30px;
  --r-pill: 999px;

  /* Type */
  --font-display: 'Bebas Neue', 'Inter', ui-sans-serif, system-ui, sans-serif;
  --font-body: 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif;

  /* Motion */
  --ease-out: cubic-bezier(0.165, 0.84, 0.44, 1);
  --ease-in-out: cubic-bezier(0.645, 0.045, 0.355, 1);
  --dur-link: 0.12s;
  --dur-btn: 0.16s;
  --dur-card: 0.32s;

  /* Layout */
  --container: 1220px;
  --gutter: clamp(20px, 5vw, 64px);
  --header-h: 68px;

  color-scheme: dark;
}

/* ============================================================
   2 · RESET
   ============================================================ */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

html.no-motion {
  scroll-behavior: auto;
}

body {
  background: var(--ground);
  color: var(--on-surface);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;

  /* The double-tap zoom guard that does not cost anybody their pinch. */
  touch-action: manipulation;
}

/*
  No `overflow-x: hidden` on the body, deliberately. It makes the body a scroll
  container, and `position: sticky` inside a scroll container stops sticking —
  which would silently kill the pinned beats in section 10. The only thing wide
  enough to need clipping is the hero's stadium, and `.hero` clips its own.
*/

img,
picture,
svg {
  display: block;
  max-width: 100%;
}

button,
input {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: 0;
  cursor: pointer;
}

a {
  color: inherit;
  text-decoration: none;
}

ul {
  list-style: none;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--r-xs);
}

/* Nothing is hidden from a screen reader that a sighted visitor can read. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: -100px;
  left: var(--gutter);
  z-index: 200;
  padding: 12px 20px;
  background: var(--cta);
  color: var(--on-cta);
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  font-weight: 600;
  transition: top var(--dur-btn) var(--ease-out);
}

.skip-link:focus {
  top: 0;
}

/* ============================================================
   3 · TYPE
   ============================================================
   Bebas is a condensed all-caps face. It carries headlines and numbers and
   nothing else — a paragraph set in it is unreadable, and a label set in it
   next to a number reads as a scoreboard, which is the whole point.
   ============================================================ */
.display {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 0.92;
  letter-spacing: 0.012em;
  text-wrap: balance;
}

.eyebrow {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
}

.section-title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2.4rem, 6.5vw, 4.25rem);
  line-height: 0.94;
  letter-spacing: 0.012em;
  text-wrap: balance;
}

.section-title em {
  font-style: normal;
  color: var(--accent);
}

.lede {
  font-size: clamp(1.02rem, 1.9vw, 1.18rem);
  color: var(--on-surface-variant);
  max-width: 54ch;
}

.muted {
  color: var(--on-surface-muted);
}

/* ============================================================
   4 · LAYOUT
   ============================================================ */
.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  position: relative;
  padding-block: clamp(72px, 11vw, 132px);
}

.section__head {
  display: flex;
  flex-direction: column;
  gap: 18px;
  max-width: 68ch;
  margin-bottom: clamp(40px, 6vw, 68px);
}

/* The reveal. Held at rest until an observer says the section has arrived; a
   page with no JavaScript, or a visitor who has asked for less motion, gets
   the finished state immediately rather than an invisible page. */
.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition:
    opacity 0.7s var(--ease-out),
    transform 0.7s var(--ease-out);
}

.reveal.is-in {
  opacity: 1;
  transform: none;
}

html.no-js .reveal,
html.no-motion .reveal {
  opacity: 1;
  transform: none;
  transition: none;
}

/* ============================================================
   5 · BUTTONS
   ============================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 52px;
  padding: 0 28px;
  border-radius: var(--r-pill);
  font-weight: 600;
  font-size: 1rem;
  letter-spacing: 0.005em;
  white-space: nowrap;
  transition:
    background-color var(--dur-btn) var(--ease-out),
    color var(--dur-btn) var(--ease-out),
    transform var(--dur-btn) var(--ease-out),
    box-shadow var(--dur-btn) var(--ease-out);
}

.btn--primary {
  background: var(--cta);
  color: var(--on-cta);
  box-shadow: 0 10px 34px rgba(var(--accent-rgb), 0.24);
}

.btn--primary:hover {
  background: var(--cta-hover);
  transform: translateY(-2px);
  box-shadow: 0 14px 42px rgba(var(--accent-rgb), 0.34);
}

.btn--ghost {
  background: var(--fill);
  color: var(--on-surface);
}

.btn--ghost:hover {
  background: var(--fill-hover);
  transform: translateY(-2px);
}

.btn--sm {
  min-height: 42px;
  padding: 0 20px;
  font-size: 0.9rem;
}

.btn:active {
  transform: translateY(0);
}

/* ============================================================
   6 · PRELOADER
   ============================================================
   The game's own boot splash, reproduced. It is here for continuity rather
   than for spectacle: a visitor who taps through to the game meets the same
   navy field and the same gold ring a second later, and the two read as one
   product instead of two websites.

   Shown once per session, never under reduced motion, and removed from the
   document entirely once it has finished so it can never trap a tab stop.
   ============================================================ */
.preloader {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  place-items: center;
  background: radial-gradient(circle at 50% 42%, var(--cc-navy-800) 0%, var(--ground) 68%);
  transition: opacity 0.45s var(--ease-out);
}

.preloader.is-done {
  opacity: 0;
  pointer-events: none;
}

.preloader__inner {
  display: grid;
  place-items: center;
  gap: 22px;
}

.preloader__mark {
  width: min(44vw, 210px);
  height: auto;
  filter: drop-shadow(0 10px 26px rgba(0, 0, 0, 0.6));
}

.preloader__ring {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 3px solid rgba(var(--accent-rgb), 0.18);
  border-top-color: var(--accent);
  animation: ring-spin 900ms linear infinite;
}

@keyframes ring-spin {
  to {
    transform: rotate(360deg);
  }
}

/* ============================================================
   7 · HEADER
   ============================================================ */
.header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  height: var(--header-h);
  display: flex;
  align-items: center;
  transition:
    background-color 0.3s var(--ease-out),
    backdrop-filter 0.3s var(--ease-out);
}

.header.is-stuck {
  background: rgba(4, 9, 26, 0.82);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  width: 100%;
}

.header__brand {
  display: flex;
  align-items: center;
  gap: 11px;
  font-family: var(--font-display);
  font-size: 1.35rem;
  letter-spacing: 0.04em;
}

.header__brand img {
  width: 30px;
  height: 30px;
  object-fit: contain;
}

.header__nav {
  display: none;
  align-items: center;
  gap: 30px;
}

.header__link {
  display: inline-flex;
  align-items: center;
  min-height: 28px;
  font-size: 0.92rem;
  color: var(--on-surface-variant);
  transition: color var(--dur-link) var(--ease-out);
}

.header__link:hover {
  color: var(--on-surface);
}

@media (min-width: 62rem) {
  .header__nav {
    display: flex;
  }
}

/* ============================================================
   8 · HERO
   ============================================================
   Three plates and a coin.

   The captains in the front plate are looking up, at nothing, in the source
   art. The coin is thrown into exactly the gap they are looking into — which
   is the only reason to spend three images on a background rather than one.
   ============================================================ */
.hero {
  position: relative;
  min-height: 100svh;

  /*
    A column with the two halves pushed apart: the coin and its control at the
    top, the copy at the bottom, both in ordinary flow. They cannot overlap at
    any viewport height, which is the whole point — the previous arrangement
    placed the control at a percentage of the hero's height while the copy sat
    in flow, and two coordinate systems only agree at the one screen size
    somebody happened to check.

    A wide screen swaps back to a row and places the coin and the control
    independently, because there the picture and the words are side by side and
    there is room to put each exactly where it belongs.
  */
  display: flex;
  flex-direction: column;

  /*
    The spare height is split between the two halves rather than all poured into
    the middle. `space-between` put the coin hard against the header and left a
    dead band under it on a tall phone; two auto margins share the slack, so the
    coin drops to about a third of the way down and the gap below it halves.

    The `gap` is the floor. On a short phone there is no slack to share and the
    hero simply grows past the viewport, which is the honest outcome — better a
    little scroll than a control resting on a headline.
  */
  justify-content: flex-start;
  gap: clamp(22px, 4vh, 56px);
  padding-top: calc(var(--header-h) + 12px);
  padding-bottom: clamp(28px, 6vw, 76px);
  overflow: hidden;
  isolation: isolate;

  /*
    Where the eye is meant to go: the captains, the coin, its shadow and the
    throw button all hang off this one number.

    On a phone it is the middle, because there is no room for it to be anywhere
    else and the copy sits over the picture with the veil carrying it. On a wide
    screen it moves right, which clears the left third for the headline — the
    two captains stop being something the type has to fight and become
    something it sits beside.
  */
  --focus-x: 50%;
}

.hero__stage {
  position: absolute;
  inset: 0;
  z-index: -2;
  pointer-events: none;
}

/*
  Three plates, sized three different ways, because they are three different
  kinds of picture.

  The sky is a backdrop and simply covers. The stands are a horizon and are
  anchored to the bottom edge, made wide enough that a tall narrow viewport
  still meets floodlights rather than the end of the image. The captains are
  figures: they are sized by their own height, so they stand a fixed fraction
  of the screen tall at every width instead of being cropped into a torso.
*/
.hero__plate {
  position: absolute;
  will-change: transform;
  pointer-events: none;
}

.hero__plate--sky {
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center center;
}

/* Full width, anchored to the bottom edge, so it reads as a horizon under the
   sky. This used to say `max(100%, 165vh)`, meaning to keep the bowl wide on a
   tall narrow screen — but the reset caps every image at `max-width: 100%`, so
   the second term never once won. Code that has never run should say so by not
   being here. */
.hero__plate--stands {
  left: 50%;
  bottom: 0;
  translate: -50% 0;
  width: 100%;
  height: auto;
  opacity: 0.92;
}

.hero__plate--captains {
  left: var(--focus-x);
  bottom: 0;
  translate: -50% 0;
  height: clamp(230px, 46vh, 620px);
  width: auto;
  max-width: none;
  filter: drop-shadow(0 24px 60px rgba(0, 0, 0, 0.6));
}

@media (min-width: 62rem) {
  .hero {
    --focus-x: 66%;
  }

  .hero__plate--captains {
    height: clamp(320px, 66vh, 780px);
  }
}

/* The ground has to win the bottom third back off the picture, or nothing set
   over it is legible. A gradient, not an overlay box, so the stadium keeps its
   floodlights at the top. */
.hero__veil {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    linear-gradient(
      to bottom,
      rgba(4, 9, 26, 0.7) 0%,
      rgba(4, 9, 26, 0.1) 24%,
      rgba(4, 9, 26, 0.34) 68%,
      var(--ground) 99%
    ),
    radial-gradient(64% 42% at var(--focus-x) 30%, rgba(var(--accent-rgb), 0.16) 0%, transparent 72%);
}

/*
  A second veil, and the reason it is separate: on a phone the copy sits
  directly on top of the picture and needs the ground beneath it darkened, but
  on a wide screen the copy has moved off the captains and the same darkening
  would only flatten the stadium for no reason. One gradient cannot be both, so
  there are two.
*/
.hero__veil::after {
  content: '';
  position: absolute;
  inset: 0;

  /*
    On a phone the copy sits along the BOTTOM, so the darkening runs down the
    page. Sweeping it left-to-right here — the desktop shape, narrowed — dimmed
    the stadium behind the top half for no reason and left the stands invisible.
    Darken where the words are, and nowhere else.
  */
  background: linear-gradient(
    to bottom,
    transparent 0%,
    rgba(4, 9, 26, 0.2) 36%,
    rgba(4, 9, 26, 0.56) 60%,
    rgba(4, 9, 26, 0.72) 100%
  );
}

@media (min-width: 62rem) {
  .hero__veil::after {
    background: linear-gradient(
      to right,
      rgba(4, 9, 26, 0.8) 0%,
      rgba(4, 9, 26, 0.42) 34%,
      transparent 62%
    );
  }
}

.hero__inner {
  position: relative;
  z-index: 2;
  width: 100%;
  margin-top: auto;
}

/* The group. In flow on a phone, a full-bleed layer on a wide screen — see the
   note on `.hero` for why. */
.hero__pitch {
  position: relative;
  z-index: 2;
  margin-top: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(12px, 2.4vh, 26px);
}

.hero__copy {
  display: flex;
  flex-direction: column;
  gap: 18px;
  /* Wide enough that each half of the headline stays on its own single line,
     which is the whole shape of the sentence: two calls, one each. */
  max-width: min(560px, 100%);
}

.hero__title {
  font-size: clamp(2.9rem, 8.4vw, 5.6rem);
}

.hero__title span {
  display: block;
}

.hero__title .is-accent {
  color: var(--accent);
}

.hero__lede {
  max-width: 46ch;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 8px;
}

/* The coin's home. Bottom-anchored in the gap between the two captains, sized
   off the viewport so it stays in that gap at every width. */
.hero__coin-slot {
  position: relative;
  flex: none;
  width: clamp(92px, 26vw, 124px);
  aspect-ratio: 1;
}

/* Inside the slot now, so it travels with the coin at every size and there is
   one thing to place instead of two things to keep in agreement. */
.hero__coin-shadow {
  position: absolute;
  left: 50%;
  bottom: -14px;
  z-index: -1;
  width: 82%;
  height: 14px;
  translate: -50% 0;
  background: radial-gradient(ellipse, rgba(0, 0, 0, 0.55), transparent 70%);
  pointer-events: none;
}

/*
  The phone gets a different composition, not a squeezed one.

  A narrow screen has no room for picture and words side by side, so they take
  turns down the page instead: the coin in the clear air at the top, the throw
  under it, and the copy along the bottom over a veil that has been asked to do
  more work. The first arrangement put the coin straight through the headline
  and the throw button on top of a real one — which is what happens when a
  desktop layout is only made narrower.
*/
.hero__toss {
  position: relative;
  z-index: 3;
  display: inline-flex;
  align-items: center;

  /* No flex gap. The result sits to the right of the label and carries its own
     margin, so that before the first throw — when there is no result — the
     label is genuinely centred in the pill rather than centred around a gap
     and a reserved slot that are holding space for nothing. */
  gap: 0;
  padding: 9px 18px;
  border-radius: var(--r-pill);
  background: rgba(4, 9, 26, 0.55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: var(--on-surface-variant);
  font-size: 0.82rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  white-space: nowrap;
  transition:
    color var(--dur-btn) var(--ease-out),
    background-color var(--dur-btn) var(--ease-out);
}

.hero__toss:hover {
  color: var(--on-surface);
  background: rgba(4, 9, 26, 0.75);
}

.hero__toss .call {
  font-family: var(--font-display);
  font-size: 1.05rem;
  letter-spacing: 0.06em;
  color: var(--accent);
  text-align: left;
}

/* Only once there is something to say. `min-width` holds the pill still between
   Heads and Tails; before the first throw it takes no room at all. */
.hero__toss .call:not(:empty) {
  min-width: 3.4em;
  margin-left: 9px;
}

/*
  The invitation.

  Added by js/coin.js rather than written into the markup, so it only ever
  appears on a page where the button actually works — a glow promising
  something a broken script cannot deliver is worse than no glow. Removed the
  first time the coin is thrown: once somebody knows the control is there, the
  pulse is just movement.
*/
.hero__toss.is-inviting {
  color: var(--on-surface);
  box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), 0.34);
}

.hero__toss.is-inviting::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  animation: toss-invite 2800ms var(--ease-out) infinite;
}

@keyframes toss-invite {
  0% {
    box-shadow: 0 0 0 0 rgba(var(--accent-rgb), 0.34);
  }
  62% {
    box-shadow: 0 0 0 13px rgba(var(--accent-rgb), 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(var(--accent-rgb), 0);
  }
}

/* Reduced motion keeps the affordance and drops the movement: a steady ring
   says "this is a control" just as well as a pulsing one. */
@media (prefers-reduced-motion: reduce) {
  .hero__toss.is-inviting::before {
    animation: none;
    box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.16);
  }
}

html.no-motion .hero__toss.is-inviting::before {
  animation: none;
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.16);
}

/* The trust strip. Four facts, none of them adjectives. */
/* Held to the width of the copy above it. Left to the container it would draw
   a rule straight across the two captains, which reads as a mistake. */
.trust {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 26px;
  max-width: min(560px, 100%);
  margin-top: 28px;
  padding-top: 22px;
  border-top: 1px solid rgba(var(--ink-rgb), 0.09);
  font-size: 0.86rem;
  color: var(--on-surface-muted);
}

.trust li {
  display: flex;
  align-items: center;
  gap: 9px;
}

.trust li::before {
  content: '';
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
  flex: none;
}

.trust b {
  color: var(--on-surface);
  font-weight: 600;
}

/* ============================================================
   THE HERO'S BREAKPOINTS
   ============================================================
   The rule for this whole stylesheet, written down here because this is where
   it kept being broken: **a media query must come after every rule it
   overrides.**

   A media query adds no specificity of its own. An override written above the
   rule it means to override simply loses, and it loses silently — the symptom
   is never "that block is in the wrong place", it is a throw button resting on
   a headline, or a control flung off the top of the screen because its
   `bottom` applied and its `position` did not. That happened three times while
   this file was being written.

   So the hero's breakpoints sit at the bottom of the hero's section, after the
   last base rule. Elsewhere in the file the same invariant holds locally: each
   breakpoint follows the rules it modifies.
   ============================================================ */

@media (max-width: 61.99rem) {
  .hero__plate--captains {
    height: clamp(220px, 38vh, 340px);
  }

  .hero__title {
    line-height: 0.9;
  }

  .hero__copy {
    gap: 14px;
  }

  /* Stacked and full width. Half-wrapped buttons read as a mistake; two full
     width ones read as a choice. */
  .hero__actions {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
  }

  .hero__actions .btn {
    width: 100%;
  }

  .trust {
    margin-top: 20px;
    padding-top: 16px;
    gap: 8px 20px;
    font-size: 0.82rem;
  }
}

@media (min-width: 62rem) {
  .hero {
    flex-direction: row;
    align-items: center;
    padding-top: calc(var(--header-h) + 20px);
  }

  /*
    Not `display: contents` — Safari used to drop those children out of the
    accessibility tree, and one of them is a button. An inset layer gives the
    same coordinate space with none of that.

    **Above `.hero__inner`, not below it.** This layer spans the whole hero, and
    so does the copy container: a full-width block with the headline in it. At
    z-index 1 against the container's 2, the container sat on top of the throw
    button and swallowed every click on desktop — the button was there, styled,
    focusable and completely dead, because `elementFromPoint` over it returned
    the container. `pointer-events: none` here is what lets this layer sit on
    top without taking the copy's own links away from it; the button inside
    turns them back on for itself and nothing else does.
  */
  .hero__pitch {
    position: absolute;
    inset: 0;
    display: block;
    padding: 0;
    z-index: 3;
    pointer-events: none;
  }

  /* Above their heads, because that is what they are looking at. */
  .hero__coin-slot {
    position: absolute;
    left: var(--focus-x);
    bottom: 62%;
    width: clamp(96px, 9vw, 124px);
    translate: -50% 0;
  }

  /* And the control down in the gap between their bodies. Any higher and it
     lands on somebody's chin. */
  .hero__toss {
    position: absolute;
    left: var(--focus-x);
    bottom: 22%;
    translate: -50% 0;
    pointer-events: auto;
  }
}

/* A tap target over the coin, so "throw it" is a real control with a real
   focus ring rather than a click handler on a decoration. */

/* ============================================================
   9 · THE COIN
   ============================================================
   Ported from the studio site, which ported it from the game. The flight
   maths lives in js/coin.js; this is only the scaffolding it writes to.

   Two rules matter. The faces sit in a preserve-3d context so a rotateX
   actually turns a disc rather than squashing a picture. The rims sit outside
   it, because at the moment the coin is edge-on both faces project to zero
   height and there is nothing left to intersect.
   ============================================================ */
.coin {
  position: absolute;
  inset: 0;
  perspective: 640px;
}

.coin__fly {
  position: absolute;
  inset: 0;
  will-change: transform;
}

.coin.is-resting .coin__fly {
  animation: coin-rest 5200ms var(--ease-in-out) infinite;
}

@keyframes coin-rest {
  0%,
  100% {
    transform: translateY(0) rotate(0deg);
  }
  50% {
    transform: translateY(-3.5%) rotate(1deg);
  }
}

.coin__spin {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  will-change: transform;
}

.coin__face {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  filter: drop-shadow(0 10px 24px rgba(0, 0, 0, 0.55));
}

.coin__face--back {
  transform: rotateX(180deg);
}

.coin__rim {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
}

/* One asset in two orientations: --flip is the horizontal sliver the rotateX
   flight passes through twice a turn, --edge is the upright rim. The width is
   a real coin's thickness rather than the projection of a squeezed face, and
   the artwork's own alpha carries the silhouette — so no border-radius. */
.coin__rim i {
  display: block;
  position: absolute;
  left: 50%;
  top: 50%;
  width: 9.5%;
  height: 98%;
  background-image:
    url('../assets/coin-edge.webp'),
    linear-gradient(
      90deg,
      #5c4610 0%,
      var(--cc-gold-700) 16%,
      var(--cc-gold-300) 46%,
      var(--cc-gold-400) 58%,
      var(--cc-gold-700) 84%,
      #5c4610 100%
    );
  background-size:
    100% 100%,
    100% 100%;
  background-repeat: no-repeat;
}

.coin__rim--edge i {
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 0 22px rgba(var(--accent-rgb), 0.5));
}

.coin__rim--flip i {
  transform: translate(-50%, -50%) rotate(90deg);
}

/* ============================================================
   10 · THE ROUND — three beats
   ============================================================
   On a wide screen the scene holds still and the beats advance over it. On a
   phone it does not pin: three stacked panels, each arriving on its own. That
   is not a fallback, it is the design — a pinned scroll section on iOS Safari
   is where this kind of thing reliably comes apart, and the phone is the
   acceptance test.
   ============================================================ */
.round {
  background: linear-gradient(to bottom, var(--ground) 0%, var(--surface) 40%, var(--ground) 100%);
}

.beats {
  display: flex;
  flex-direction: column;
  gap: clamp(28px, 5vw, 44px);
}


.beat {
  position: relative;
  display: grid;
  gap: 22px;
  padding: clamp(26px, 4vw, 40px);
  background: var(--surface-high);
  border-radius: var(--r-panel);
  overflow: hidden;
}

.beat__index {
  font-family: var(--font-display);
  font-size: clamp(2.6rem, 5vw, 3.6rem);
  line-height: 1;
  color: var(--accent);
  opacity: 0.55;
}

.beat__title {
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 4vw, 2.6rem);
  line-height: 1;
  letter-spacing: 0.015em;
}

.beat__body {
  color: var(--on-surface-variant);
  max-width: 46ch;
}

.beat__art {
  position: relative;
  min-height: 168px;
  border-radius: var(--r-card);
  background: var(--surface-higher);
  overflow: hidden;
  display: grid;
  place-items: center;
}

@media (min-width: 54rem) {
  .beat {
    grid-template-columns: 4rem 1fr 1.05fr;
    align-items: center;
    gap: 34px;
  }

  .beat__art {
    min-height: 210px;
  }
}

/*
  The pin, on a wide screen only, and done with `position: sticky` rather than
  with a scroll library.

  Each beat holds at its own offset while the next one slides up over it,
  leaving a sliver of the one behind — so the three read as one sequence being
  advanced rather than three cards being scrolled past. Nothing is scroll
  jacked: the page still moves exactly as far as the reader pushes it, which is
  the difference between this and the version that falls apart on iOS.

  Below 62rem it is simply not applied, and the beats are three stacked panels.
  That is the design, not a fallback.
*/
@media (min-width: 62rem) {
  .beats {
    gap: 0;
  }

  .beat {
    position: sticky;
    top: calc(var(--header-h) + 32px);
    box-shadow: 0 -24px 60px rgba(4, 9, 26, 0.5);
  }

  .beat + .beat {
    margin-top: clamp(120px, 16vh, 200px);
  }

  .beat:nth-child(2) {
    top: calc(var(--header-h) + 64px);
  }

  .beat:nth-child(3) {
    top: calc(var(--header-h) + 96px);
  }
}

/* Beat one: the two calls. */
.calls {
  display: flex;
  gap: 14px;
}

.call-chip {
  display: grid;
  place-items: center;
  gap: 6px;
  width: 92px;
  padding: 16px 10px;
  border-radius: var(--r-md);
  background: var(--fill);
  transition:
    background-color var(--dur-card) var(--ease-out),
    box-shadow var(--dur-card) var(--ease-out),
    transform var(--dur-card) var(--ease-out);
}

.call-chip__face {
  width: 46px;
  height: 46px;
  object-fit: contain;
}

.call-chip__label {
  font-family: var(--font-display);
  font-size: 1.15rem;
  letter-spacing: 0.07em;
  color: var(--on-surface-variant);
}

.call-chip.is-lit {
  background: rgba(var(--accent-rgb), 0.14);
  box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), 0.42);
  transform: translateY(-3px);
}

.call-chip.is-lit .call-chip__label {
  color: var(--accent-bright);
}

/* Beat two: the arc the coin travels, drawn rather than described. */
.arc {
  width: 100%;
  height: 100%;
  max-height: 190px;
}

.arc__path {
  fill: none;
  stroke: rgba(var(--accent-rgb), 0.3);
  stroke-width: 2;
  stroke-dasharray: 5 7;
}

.arc__travel {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2.5;
  stroke-linecap: round;
}

.arc__coin {
  fill: var(--accent-bright);
  filter: drop-shadow(0 0 10px rgba(var(--accent-rgb), 0.75));
}

/* Beat three: the two cards, and what the pick is worth. */
.beat__art--call {
  padding: 20px;
  gap: 12px;
  grid-auto-flow: column;
}

/* ============================================================
   11 · BAT OR BOWL
   ============================================================ */
.choice {
  background: var(--surface);
}

.choice__grid {
  display: grid;
  gap: clamp(18px, 3vw, 26px);
}

@media (min-width: 48rem) {
  .choice__grid {
    grid-template-columns: 1fr 1fr;
  }
}

.choice-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: clamp(24px, 3.4vw, 36px);
  border-radius: var(--r-panel);
  background: var(--surface-high);
  text-align: left;
  overflow: hidden;
  transition:
    background-color var(--dur-card) var(--ease-out),
    transform var(--dur-card) var(--ease-out),
    box-shadow var(--dur-card) var(--ease-out);
}

.choice-card::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(80% 60% at 50% 0%, rgba(var(--tint), 0.22) 0%, transparent 70%);
  opacity: 0;
  transition: opacity var(--dur-card) var(--ease-out);
}

.choice-card--bat {
  --tint: 47, 107, 229;
}

.choice-card--bowl {
  --tint: 216, 53, 63;
}

.choice-card:hover,
.choice-card.is-chosen {
  transform: translateY(-4px);
  background: var(--surface-higher);
}

.choice-card:hover::after,
.choice-card.is-chosen::after {
  opacity: 1;
}

.choice-card.is-chosen {
  box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), 0.45);
}

.choice-card__kicker {
  font-family: var(--font-display);
  font-size: 2.1rem;
  line-height: 1;
  letter-spacing: 0.05em;
}

.choice-card__art {
  width: 68px;
  height: 68px;
  object-fit: contain;
}

.choice-card__body {
  color: var(--on-surface-variant);
  font-size: 0.96rem;
}

.choice-card__hint {
  margin-top: auto;
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--on-surface-faint);
  transition: color var(--dur-card) var(--ease-out);
}

.choice-card.is-chosen .choice-card__hint {
  color: var(--accent);
}

/* The ladder. One row per outcome, the bar showing how often it lands, the
   multiplier showing what it pays. The labels change with the pick; the money
   does not, because it is the same row of the same table. */
.ladder {
  margin-top: clamp(30px, 4vw, 46px);
  border-radius: var(--r-panel);
  background: var(--surface-high);
  padding: clamp(20px, 3vw, 32px);
}

.ladder__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px 20px;
  margin-bottom: 20px;
}

.ladder__title {
  font-family: var(--font-display);
  font-size: 1.5rem;
  letter-spacing: 0.03em;
}

.ladder__note {
  font-size: 0.85rem;
  color: var(--on-surface-muted);
}

.ladder__rows {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.rung {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 6px 16px;
  padding: 11px 0;
  border-top: 1px solid rgba(var(--ink-rgb), 0.06);
}

.rung:first-child {
  border-top: 0;
}

.rung__label {
  font-weight: 550;
  font-size: 0.98rem;
}

.rung__mult {
  font-family: var(--font-display);
  font-size: 1.4rem;
  letter-spacing: 0.03em;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.rung--out .rung__mult {
  color: var(--on-surface-faint);
}

.rung__bar {
  grid-column: 1 / -1;
  height: 4px;
  border-radius: var(--r-pill);
  background: rgba(var(--ink-rgb), 0.07);
  overflow: hidden;
}

.rung__fill {
  display: block;
  height: 100%;
  border-radius: var(--r-pill);
  background: var(--accent);
  transform-origin: left;
  transition: transform 0.6s var(--ease-out);
}

.rung--out .rung__fill {
  background: var(--on-surface-faint);
}

.rung__blurb {
  grid-column: 1 / -1;
  font-size: 0.86rem;
  color: var(--on-surface-muted);
}

/* ============================================================
   12 · BONUSES
   ============================================================ */
.bonuses__grid {
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 232px), 1fr));
}

.bonus-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 26px 24px 24px;
  border-radius: var(--r-card);
  background: var(--surface-high);
  transition:
    background-color var(--dur-card) var(--ease-out),
    transform var(--dur-card) var(--ease-out);
}

.bonus-card:hover {
  background: var(--surface-higher);
  transform: translateY(-4px);
}

.bonus-card__icon {
  width: 46px;
  height: 46px;
  object-fit: contain;
}

.bonus-card__name {
  font-family: var(--font-display);
  font-size: 1.45rem;
  letter-spacing: 0.035em;
}

.bonus-card__mult {
  font-family: var(--font-display);
  font-size: 1.45rem;
  letter-spacing: 0.03em;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.bonus-card__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.bonus-card__body {
  font-size: 0.9rem;
  color: var(--on-surface-muted);
}

/* ============================================================
   13 · FAIRNESS
   ============================================================
   The one section that should read technical rather than glossy, so it is set
   like a terminal rather than like a feature card.
   ============================================================ */
.fair {
  background: var(--surface);
}

.fair__grid {
  display: grid;
  gap: clamp(28px, 4vw, 52px);
  align-items: start;
}

@media (min-width: 58rem) {
  .fair__grid {
    grid-template-columns: 1fr 1fr;
  }
}

.steps {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.step {
  display: grid;
  grid-template-columns: 2.4rem 1fr;
  gap: 4px 14px;
  padding: 18px 0;
  border-top: 1px solid rgba(var(--ink-rgb), 0.07);
}

.step:first-child {
  border-top: 0;
}

.step__n {
  font-family: var(--font-display);
  font-size: 1.5rem;
  line-height: 1.1;
  color: var(--accent);
}

.step__title {
  font-weight: 620;
}

.step__body {
  grid-column: 2;
  font-size: 0.93rem;
  color: var(--on-surface-muted);
}

.terminal {
  border-radius: var(--r-card);
  background: var(--cc-navy-950);
  padding: 22px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.78rem;
  line-height: 1.85;
  overflow-x: auto;
}

.terminal__line {
  display: block;
  white-space: nowrap;
  color: var(--on-surface-muted);
}

/* A 64-character hash will not fit a phone on one line, and making the panel
   scroll sideways to read it is worse than letting it wrap. On a wide screen
   the single line is the better picture, so the wrap is narrow-only. */
@media (max-width: 40rem) {
  .terminal__line {
    white-space: normal;
  }
}

.terminal__key {
  color: var(--on-surface-faint);
}

.terminal__hash {
  color: var(--accent-soft);
  word-break: break-all;
}

.terminal__ok {
  color: var(--win);
}

/* ============================================================
   14 · NUMBERS
   ============================================================ */
.stats {
  display: grid;
  gap: 2px;
  border-radius: var(--r-panel);
  overflow: hidden;
  background: rgba(var(--ink-rgb), 0.06);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr));
}

.stat {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 28px 24px;
  background: var(--surface-high);
}

.stat__value {
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 5vw, 3.2rem);
  line-height: 1;
  letter-spacing: 0.02em;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.stat__label {
  font-size: 0.88rem;
  color: var(--on-surface-muted);
}

/* ============================================================
   15 · STUDIO
   ============================================================ */
.studio__panel {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: clamp(26px, 4vw, 42px);
  border-radius: var(--r-panel);
  background: var(--surface-high);
}

.studio__copy {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 46ch;
}

.studio__name {
  font-family: var(--font-display);
  font-size: 1.9rem;
  letter-spacing: 0.04em;
}

/* ============================================================
   16 · SAFER GAMBLING
   ============================================================
   A band, not mouse type. The game treats the age check as a trigger on a
   database table rather than a tickbox; the marketing surface should not be
   the weakest part of that.
   ============================================================ */
.safer {
  background: var(--surface);
}

.safer__panel {
  display: grid;
  gap: 24px;
  padding: clamp(26px, 4vw, 44px);
  border-radius: var(--r-panel);
  background: var(--surface-high);
}

@media (min-width: 54rem) {
  .safer__panel {
    grid-template-columns: auto 1fr;
    align-items: start;
    gap: 40px;
  }
}

.safer__badge {
  display: grid;
  place-items: center;
  width: 78px;
  height: 78px;
  border-radius: 50%;
  background: var(--fill);
  box-shadow: inset 0 0 0 2px var(--on-surface-faint);
  font-family: var(--font-display);
  font-size: 1.85rem;
  letter-spacing: 0.02em;
  color: var(--on-surface);
}

.safer__body {
  display: flex;
  flex-direction: column;
  gap: 14px;
  max-width: 68ch;
  font-size: 0.96rem;
  color: var(--on-surface-variant);
}

.safer__links {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 22px;
  font-size: 0.9rem;
}

/* Standalone links in a list, not links inside a sentence, so WCAG 2.2's
   inline exception does not cover them and they owe a 24px target. */
.safer__links a {
  display: inline-flex;
  align-items: center;
  min-height: 26px;
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-thickness: 1px;
}

/* ============================================================
   17 · FINAL CALL
   ============================================================ */
.final {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  text-align: center;
}

.final__bg {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 28%;
}

.final__veil {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
    to bottom,
    var(--ground) 0%,
    rgba(4, 9, 26, 0.74) 42%,
    rgba(4, 9, 26, 0.9) 100%
  );
}

.final__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 22px;
}

.final__title {
  font-size: clamp(2.8rem, 9vw, 5.6rem);
}

/* ============================================================
   18 · FOOTER
   ============================================================ */
.footer {
  padding-block: clamp(44px, 6vw, 72px);
  background: var(--ground);
  font-size: 0.88rem;
  color: var(--on-surface-muted);
}

.footer__top {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 28px;
  padding-bottom: 30px;
  border-bottom: 1px solid rgba(var(--ink-rgb), 0.07);
}

.footer__brand {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 34ch;
}

.footer__mark {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-display);
  font-size: 1.3rem;
  letter-spacing: 0.04em;
  color: var(--on-surface);
}

.footer__mark img {
  width: 26px;
  height: 26px;
  object-fit: contain;
}

.footer__cols {
  display: flex;
  flex-wrap: wrap;
  gap: 30px 56px;
}

.footer__col {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 130px;
}

.footer__col h3 {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--on-surface-faint);
  margin-bottom: 2px;
}

/* Same rule as the safer-gambling links: stacked, standalone, so each one owes
   a 24px target rather than the height of its own text. */
.footer__col a {
  display: inline-flex;
  align-items: center;
  min-height: 26px;
}

.footer__col a:hover {
  color: var(--on-surface);
}

.footer__bottom a {
  display: inline-flex;
  align-items: center;
  min-height: 26px;
  color: var(--on-surface-muted);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.footer__bottom a:hover {
  color: var(--on-surface);
}

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 14px 30px;
  padding-top: 26px;
  font-size: 0.8rem;
  color: var(--on-surface-faint);
}

/* ============================================================
   19 · LEGAL PAGES
   ============================================================ */
.legal {
  padding-top: calc(var(--header-h) + clamp(48px, 8vw, 96px));
  padding-bottom: clamp(60px, 9vw, 110px);
}

.legal__inner {
  max-width: 72ch;
}

.legal h1 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2.6rem, 8vw, 4rem);
  line-height: 0.95;
  letter-spacing: 0.015em;
  margin-bottom: 10px;
}

.legal__stamp {
  font-size: 0.85rem;
  color: var(--on-surface-faint);
  margin-bottom: 40px;
}

.legal h2 {
  font-size: 1.12rem;
  font-weight: 650;
  margin: 36px 0 10px;
}

.legal p,
.legal li {
  color: var(--on-surface-variant);
  margin-bottom: 12px;
}

.legal ul {
  list-style: disc;
  padding-left: 1.2rem;
  margin-bottom: 16px;
}

.legal li::marker {
  color: var(--accent);
}

.legal a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* ============================================================
   20 · REDUCED MOTION
   ============================================================
   The game treats this as a first-class state rather than a courtesy, and so
   does the site. Nothing loops, nothing parallaxes, nothing waits to arrive.
   ============================================================ */
/*
  Two selectors, one behaviour.

  The media query is what a visitor with Reduce Motion switched on matches. The
  class is what js/env.js writes, and the two have to agree: somebody who turns
  the setting on mid-visit gets the class straight away, and a stylesheet that
  only listened to the media query would keep the coin breathing until the next
  navigation.
*/
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .coin.is-resting .coin__fly {
    animation: none;
  }

  .hero__plate {
    transform: none !important;
  }
}

html.no-motion *,
html.no-motion *::before,
html.no-motion *::after {
  animation-duration: 0.01ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.01ms !important;
  scroll-behavior: auto !important;
}

html.no-motion .coin.is-resting .coin__fly {
  animation: none;
}

html.no-motion .hero__plate {
  transform: none !important;
}
