/* ============================================================================
   Blob League site design system.

   ONE stylesheet for every page (landing, /terms, /privacy, /account/delete) so
   arriving from a store listing never feels like a different company's site, and
   so a token change cannot land on one page and miss another.

   Measured against rocketleague.com rather than described from memory: ultra-bold
   uppercase display at line-height 1, near-sharp 4px geometry, 80px section
   rhythm, key art carrying the page. See docs/website-redesign-plan.md.

   SINGLE THEME, deliberately. The reference is dark-only and so is the game; a
   light variant would be a second design nobody asked for. Every colour is painted
   explicitly rather than inherited, so the page holds on any host background.

   Fonts are SELF-HOSTED. The legal pages go in both store listings and get opened
   by reviewers on unpredictable connections, and a legal page that depends on a
   third-party CDN is a legal page that can fail to load. Same origin + swap keeps
   that guarantee: text paints immediately in the fallback and upgrades silently.
   ========================================================================== */

/* -------------------------------------------------------------------- fonts */
@font-face {
  font-family: "Archivo Black";
  src: url("/fonts/archivo-black-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2018-201A, U+201C-201E, U+2022, U+2039-203A;
}
@font-face { font-family: "Inter"; src: url("/fonts/inter-400.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Inter"; src: url("/fonts/inter-500.woff2") format("woff2"); font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: "Inter"; src: url("/fonts/inter-700.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; }

/* ------------------------------------------------------------------- tokens */
:root {
  /* TWO TEMPERATURES, taken from the logo rather than invented. Sampling the
     stadium band behind the blobs returns two clusters in near-equal measure:
     cyan-blue around hue 200-219, and orange-amber around hue 19-28. That split
     IS the brand - cold stands one side, sodium-lit stands the other - and the
     previous site used none of it, which is why one accent on navy read as a
     generic dark tech page.

     The ground is deliberately NEUTRAL near-black, not navy. Navy plus a blue
     accent is a single temperature pretending to be two, and it is what made the
     old palette and its "redesign" measure identical. */
  --ground:  #0B0D12;
  --raised:  #14171E;
  --sunk:    #07080C;
  --edge:    #272C38;

  --cold:      #1A9FFF;   /* stadium blue. Primary action; the app's own accent. */
  --cold-deep: #0B63B8;
  --warm:      #F0761A;   /* stadium orange. The second temperature. */
  --warm-deep: #A8480A;
  --gold:      #FFC93C;   /* the crown. Season and reward only, never decoration. */
  --danger:    #FF5A4E;

  --text:   #F4F6FA;
  --body:   #C3CBD9;
  --muted:  #8B93A6;
  --faint:  #626A7C;

  /* Kept as aliases so the prose and form layers do not need rewriting. */
  --blue: var(--cold);
  --blue-deep: var(--cold-deep);

  /* Separators fade out at both ends rather than stopping dead against nothing.
     Applied through border-image, so an existing `border-top: 1px solid` becomes a
     fading rule by adding one line - no pseudo-elements, no markup. Note that
     border-image cancels border-radius, which none of these rules use. */
  --rule-x: linear-gradient(to right,  transparent, var(--edge) 12%, var(--edge) 88%, transparent);
  --rule-y: linear-gradient(to bottom, transparent, var(--edge) 12%, var(--edge) 88%, transparent);
  /* How far a screenshot or clip dissolves into the page at each edge. Big enough
     to lose the hard rectangle, small enough that content near the edge - the
     quests tab row, say - stays readable. */
  --fade: 34px;
  --edge-fade-x: linear-gradient(to right,  transparent 0, #000 var(--fade), #000 calc(100% - var(--fade)), transparent 100%);
  --edge-fade-y: linear-gradient(to bottom, transparent 0, #000 var(--fade), #000 calc(100% - var(--fade)), transparent 100%);

  --r: 4px;

  --shell: 78rem;
  --section: 84px;

  --display: "Archivo Black", "Arial Black", "Helvetica Neue", Impact, sans-serif;
  --sans: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  color-scheme: dark;
}

/* --------------------------------------------------------------------- base */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--ground);
  color: var(--body);
  font: 400 16px/1.6 var(--sans);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, svg, video { max-width: 100%; height: auto; display: block; }

/* Every focusable thing keeps a visible ring. The old site got this right and it
   would be easy to lose in a restyle. */
:where(a, button, input, [tabindex]):focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
  border-radius: 2px;
}

/* The topbar is sticky, so an in-page jump lands the target UNDER it: #news would
   scroll the heading out of sight behind the bar. Reserve its height plus a little
   air on anything addressable. Also fixes the focus ring being hidden when keyboard
   navigation moves to an anchored section. */
:where([id]) { scroll-margin-top: calc(68px + 1.25rem); }

/* Keyboard and screen-reader users get past the nav in one keystroke. Off-screen
   until focused, then it becomes a real, visible control rather than a hint. */
.skip {
  position: absolute; left: .75rem; top: -100%; z-index: 50;
  background: var(--blue); color: #04121F;
  font: 700 .85rem/1 var(--sans); text-transform: uppercase; letter-spacing: .06em;
  padding: .8rem 1.2rem; border-radius: var(--r); text-decoration: none;
}
:where(.skip):focus, :where(.skip):focus-visible { top: .75rem; }

.shell { width: 100%; max-width: var(--shell); margin: 0 auto; padding: 0 1.5rem; }
/* padding-block, NOT the `padding: X 0` shorthand. Sections carry .shell too, and
   the shorthand reset .shell's inline padding to zero - invisible above 1296px
   where max-width does the insetting, but every narrower viewport had its text
   running into both screen edges. */
.section { padding-block: var(--section); }
/* Two stacked sections would otherwise put a full pad on each side of the seam -
   192px of empty ground between two feature rows, which reads as unfinished rather
   than airy. The seam gets one and a bit pads; the page's outer edges keep two. */
.section + .section { padding-block-start: calc(var(--section) * .42); }
@media (max-width: 46rem) { :root { --section: 56px; --fade: 18px; } }

/* --------------------------------------------------------------- typography */
/* Display is ALWAYS uppercase at leading 1. That single rule is the biggest lever
   between an indie game page and a published one. Tracking -0.5% per the `nike`
   pack's substitution note, to approximate a proprietary face's optical weight. */
.d1, .d2, .d3 {
  font-family: var(--display);
  font-weight: 400;              /* the face is already ultra-bold */
  text-transform: uppercase;
  line-height: 1;
  letter-spacing: -0.005em;
  color: var(--text);
  margin: 0;
  text-wrap: balance;
}
/* Archivo Black is WIDE, so headlines eat horizontal space fast. Keep them to
   3-5 words; the clamp floors are set low enough to survive a long one. */
.d1 { font-size: clamp(2.4rem, 6.4vw, 5rem); }
.d2 { font-size: clamp(1.7rem, 3.4vw, 2.5rem); }
.d3 { font-size: clamp(1.05rem, 1.7vw, 1.3rem); }

.lede { font-size: 1.1rem; color: var(--muted); max-width: 34rem; margin: 1.25rem 0 0; }
.eyebrow {
  font: 500 0.78rem/1 var(--sans);
  text-transform: uppercase; letter-spacing: 0.16em;
  color: var(--gold); margin: 0 0 1rem;
}
.num { font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------------ buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: .5rem; white-space: nowrap;          /* a wrapped CTA is a broken CTA */
  font: 700 .95rem/1 var(--sans);
  text-transform: uppercase; letter-spacing: .06em;
  padding: .95rem 1.6rem; border: 0; border-radius: var(--r);
  text-decoration: none; cursor: pointer;
  transition: transform .12s ease, background-color .12s ease, border-color .12s ease;
}
.btn-primary { background: var(--blue); color: #04121F; }        /* dark ink on blue: AA at this size */
.btn-primary:hover { background: #3FB0FF; }
.btn-ghost { background: transparent; color: var(--text); border: 1px solid var(--edge); }
.btn-ghost:hover { border-color: var(--blue); color: var(--blue); }
.btn:active { transform: translateY(1px); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; transform: none; }
@media (prefers-reduced-motion: reduce) { .btn { transition: none; } .btn:active { transform: none; } }

/* ----------------------------------------------------------------- topbar */
/* The crest is a detailed illustration - three blobs, a crown, a stadium AND the
   wordmark inside it. At 30px it is unreadable mush, and next to a text wordmark
   it says "Blob League" twice. So the bar carries the LOGOTYPE only, set in the
   display face; the crest lives in the hero where it is big enough to read.

   Links sit next to the wordmark rather than floating against the right edge,
   which removes the dead gulf across the middle, and the right edge carries one
   real action so the bar has a purpose and a hierarchy instead of four
   identical-weight links. */
.topbar {
  position: sticky; top: 0; z-index: 20;
  background: rgba(11, 13, 18, .82);
  backdrop-filter: blur(14px) saturate(140%); -webkit-backdrop-filter: blur(14px) saturate(140%);
  border-bottom: 1px solid var(--edge); border-image: var(--rule-x) 1;
}
.topbar .in { display: flex; align-items: center; gap: 2.5rem; height: 72px; }
.mark { display: flex; align-items: center; text-decoration: none; flex: none; }
.mark b {
  font-family: var(--display); text-transform: uppercase;
  font-size: 1.06rem; line-height: 1; color: var(--text); letter-spacing: -.01em;
}
/* The warm dot is the one place the second temperature appears in the chrome. It
   is a brand mark, not a status light, so it never changes meaning. */
.mark b::after {
  content: ""; display: inline-block; width: .34em; height: .34em;
  margin-left: .34em; border-radius: 50%; background: var(--warm);
  vertical-align: .12em;
}
.topbar nav { display: flex; gap: 1.9rem; margin-right: auto; }
.topbar nav a {
  font: 500 .82rem/1 var(--sans); text-transform: uppercase; letter-spacing: .12em;
  color: var(--muted); text-decoration: none;
  padding: .55rem 0; position: relative;
}
.topbar nav a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--warm); transform: scaleX(0); transform-origin: left;
  transition: transform .16s ease;
}
.topbar nav a:hover { color: var(--text); }
.topbar nav a:hover::after, .topbar nav a[aria-current="page"]::after { transform: scaleX(1); }
.topbar nav a[aria-current="page"] { color: var(--text); }
@media (prefers-reduced-motion: reduce) { .topbar nav a::after { transition: none; } }

.topbar .nav-cta {
  flex: none;
  font: 700 .78rem/1 var(--sans); text-transform: uppercase; letter-spacing: .1em;
  color: var(--text); text-decoration: none;
  padding: .7rem 1.1rem; border: 1px solid var(--edge); border-radius: var(--r);
  transition: border-color .14s ease, color .14s ease;
}
.topbar .nav-cta:hover { border-color: var(--warm); color: var(--warm); }
@media (prefers-reduced-motion: reduce) { .topbar .nav-cta { transition: none; } }

@media (max-width: 62rem) {
  .topbar .in { gap: 1.5rem; }
  .topbar nav { gap: 1.2rem; }
  .topbar nav a { font-size: .76rem; letter-spacing: .08em; }
}
@media (max-width: 46rem) {
  .topbar nav a[data-nav="secondary"] { display: none; }
}
@media (max-width: 30rem) {
  .topbar .nav-cta { display: none; }   /* the status strip below carries it */
  .topbar nav { gap: 1rem; }
}

/* ------------------------------------------------------------------ footer */
.foot { background: var(--sunk); border-top: 1px solid var(--edge); border-image: var(--rule-x) 1; padding: 3.5rem 0 3rem; margin-top: var(--section); }
.fgrid { display: flex; flex-wrap: wrap; gap: 2.5rem 4rem; }
.fcol { min-width: 10rem; }
.fcol h3 {
  font: 500 .74rem/1 var(--sans); text-transform: uppercase; letter-spacing: .16em;
  /* --muted, not --faint: at .74rem this is small text, so AA wants 4.5:1 and
     --faint measured 4.31 against --sunk. Measured, not eyeballed. */
  color: var(--muted); margin: 0 0 1rem;
}
.fcol a { display: block; color: var(--body); text-decoration: none; font-size: .93rem; padding: .3rem 0; }
.fcol a:hover { color: var(--blue); }
.legal-line { margin: 3rem 0 0; padding-top: 1.5rem; border-top: 1px solid var(--edge); border-image: var(--rule-x) 1; color: var(--muted); font-size: .85rem; }

/* ============================================================================
   PROSE - the legal documents (/terms, /privacy) and the account pages.

   These URLs sit in both store listings and get opened by reviewers, so the
   priority is reading comfort over expression: a narrower measure, larger body
   text, and display type used only for the page title. The chrome matches the
   landing page so arriving here from a store listing does not feel like landing
   on a different company's site.
   ========================================================================== */
.prose-shell { max-width: 46rem; margin: 0 auto; padding: 3.5rem 1.5rem 4rem; }

.prose { font-size: 1.02rem; line-height: 1.75; color: var(--body); }
.prose > h1 { /* the document title, set in display like every other page heading */
  font-family: var(--display); text-transform: uppercase; line-height: 1;
  letter-spacing: -.005em; color: var(--text);
  font-size: clamp(1.9rem, 4vw, 2.75rem); margin: 0 0 1.5rem;
}
.prose h2 {
  font-family: var(--display); text-transform: uppercase; line-height: 1.1;
  letter-spacing: -.005em; color: var(--text);
  font-size: 1.15rem; margin: 3rem 0 .8rem; padding-top: 1.5rem;
  border-top: 1px solid var(--edge); border-image: var(--rule-x) 1;
}
.prose h3 { font: 700 1rem/1.4 var(--sans); color: var(--text); margin: 1.8rem 0 .4rem; }
.prose p, .prose li { color: var(--body); }
.prose li { margin: .35rem 0; }
.prose ul, .prose ol { padding-left: 1.2rem; }
.prose a { color: var(--blue); }
.prose strong { color: var(--text); }
.prose code {
  background: var(--raised); border: 1px solid var(--edge);
  padding: .12em .4em; border-radius: var(--r); font-size: .9em; color: #B9CDEA;
}

/* The disclaimer blocks. Gold, because they are the one thing on the page a
   reader should not skim past. */
.prose blockquote {
  margin: 1.5rem 0; padding: 1.1rem 1.3rem;
  border-left: 3px solid var(--gold); border-radius: 0 var(--r) var(--r) 0;
  background: rgba(255,201,60,.07);
}
.prose blockquote p { color: #F3E2B4; margin: .4rem 0; }
.prose blockquote p:first-child { margin-top: 0; }
.prose blockquote p:last-child { margin-bottom: 0; }

/* The "what we collect and why" grid is the part people actually read, and it is
   wide. It scrolls inside its own container so the PAGE never scrolls sideways. */
.prose .tablewrap { overflow-x: auto; margin: 1.4rem 0; border: 1px solid var(--edge); border-radius: var(--r); }
.prose table { border-collapse: collapse; width: 100%; font-size: .93rem; }
/* These stay solid. A table's row rules are a data grid, not a page separator, and
   fading each CELL independently renders as a dashed line rather than a soft one. */
.prose th, .prose td { text-align: left; padding: .7rem .85rem; border-bottom: 1px solid var(--edge); vertical-align: top; }
.prose thead th { color: var(--muted); font-weight: 600; white-space: nowrap; background: var(--raised); }
.prose tbody tr:last-child td { border-bottom: 0; }

.prose hr { border: 0; border-top: 1px solid var(--edge); border-image: var(--rule-x) 1; margin: 2.5rem 0; }
/* A markdown rule immediately before an h2 stacks into a double line; the heading
   already separates the section, so the rule stands down. */
.prose hr + h2 { border-top: 0; padding-top: 0; margin-top: 0; }

.doc-meta {
  margin: 0 0 2.5rem; padding-bottom: 1.5rem; border-bottom: 1px solid var(--edge); border-image: var(--rule-x) 1;
  color: var(--faint); font-size: .85rem;
}
.doc-meta code { background: none; border: 0; padding: 0; color: var(--muted); }
