/* Clever Games — site styles.
 *
 * Tokens are lifted verbatim from the Telegram Mini App handoff
 * (docs/design-handoff/app-catalog/) so the website and the Mini App read as one product.
 * Names differ between the two files (here --accent-violet, there --accent is the gradient);
 * values do not, and must not. Any change in this Tokens block is a change in both.
 *
 * Two deliberate deviations from that handoff, both forced:
 *
 * 1. Inter is used for headings too, not Space Grotesk. Space Grotesk ships no Cyrillic
 *    (Google serves it as latin / latin-ext / vietnamese only), so on the /ru/ and /ua/ pages
 *    every heading would have silently fallen back to a system font. Inter carries full
 *    Cyrillic. Worth fixing in the Mini App design as well — it has the same three locales.
 * 2. Fonts are self-hosted rather than pulled from Google. One less third party, and no
 *    visitor IP handed to it.
 *
 * The handoff's light palette is its default; here the visitor's own preference wins, since a
 * browser tells us and Telegram's WebView does not.
 *
 * This pass adds what the pages were missing rather than what they had wrong: a section
 * rhythm, a heading scale that ranks instead of shouting in unison, and card containers for
 * the two places where a group of lines is really one object — a save, and a conflict.
 */

/* ── Fonts ──────────────────────────────────────────────────────────────────────────────── */
/* Variable weight axis, so 400–700 is one file per subset. unicode-range keeps Cyrillic from
   being downloaded on English pages and vice versa. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/inter-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/inter-cyrillic-ext.woff2') format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

/* ── Tokens ─────────────────────────────────────────────────────────────────────────────── */
:root {
  /* Brand — fixed in both schemes. */
  --accent: linear-gradient(135deg, #7c5cff, #43e7ff);
  --accent-violet: #8b74ff;
  --on-accent: #0a0b14;
  --glow: 0 6px 20px rgba(124, 92, 255, 0.45);
  --glow-sm: 0 4px 12px rgba(124, 92, 255, 0.4);

  /* Danger. One hue, two roles: the line and the label. Both schemes need their own label
     lightness, so --danger-ink is re-declared in the dark block below. */
  --danger: #e0574f;
  --danger-ink: #b23a33;

  /* Light (the handoff's default). */
  --bg: #f6f7fc;
  --surf: #ffffff;
  /* One step above --surf, for a card that sits inside a card. Nothing else earns a shade. */
  --surf-2: #f3f4fb;
  --text: #171932;
  --muted: rgba(23, 25, 50, 0.55);
  --line: rgba(23, 25, 50, 0.09);
  --chip: #eef0f8;
  --chipline: rgba(23, 25, 50, 0.1);
  --glow-violet: 0.14;
  --glow-cyan: 0.1;
  --shadow-card: 0 1px 2px rgba(23, 25, 50, 0.05), 0 8px 24px rgba(23, 25, 50, 0.05);

  --r-card: 16px;
  --r-btn: 14px;
  --r-pill: 20px;
  --r-mark: 11px;
  --maxw: 1080px;

  /* Vertical rhythm. Sections step in one of two sizes and nothing in between, which is what
     makes a page read as a stack of sections rather than a stack of paragraphs. */
  --sp-sec: clamp(40px, 6vw, 68px);
  --sp-block: 24px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0d0f1c;
    --surf: #15182b;
    --surf-2: #1c2038;
    --text: #eceeff;
    --muted: rgba(236, 238, 255, 0.55);
    --line: rgba(255, 255, 255, 0.09);
    --chip: rgba(255, 255, 255, 0.06);
    --chipline: rgba(255, 255, 255, 0.12);
    --glow-violet: 0.4;
    --glow-cyan: 0.24;
    --danger-ink: #e88b85;
    --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 24px rgba(0, 0, 0, 0.25);
  }
}

/* ── Base ───────────────────────────────────────────────────────────────────────────────── */
*,
*::before,
*::after { box-sizing: border-box; }

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

body {
  margin: 0;
  min-height: 100dvh;
  background: var(--bg);
  color: var(--text);
  font: 400 16px/1.6 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
}

/* The ambient corner glows from the handoff, moved off `body` and onto a fixed layer of their
   own. On the body they were painted with background-attachment: fixed, and their radial edge
   cut a visible horizontal line straight across whatever content happened to be at that
   scroll position. Here the same two radials are faded out vertically by a mask, so the layer
   has no edge to see: light at the top of the viewport, nothing by the middle of it. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(60ch 40ch at 0% 0%, rgba(124, 92, 255, var(--glow-violet)), transparent 70%),
    radial-gradient(60ch 40ch at 100% 0%, rgba(67, 231, 255, var(--glow-cyan)), transparent 70%);
  background-repeat: no-repeat;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, rgba(0, 0, 0, 0.5) 45%, transparent 78%);
  mask-image: linear-gradient(to bottom, #000 0%, rgba(0, 0, 0, 0.5) 45%, transparent 78%);
}

img { max-width: 100%; height: auto; display: block; }

a { color: var(--accent-violet); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ── Type scale ─────────────────────────────────────────────────────────────────────────── */
/* Four ranks, each visibly a rank apart: page title, section title, block title, label.
   Before, an h1, two h2s and a bold line inside a panel all carried roughly the same weight,
   so the page had four first-places and no order. The separation here is size *and* colour
   *and* case — one of the three alone was not enough at 15–20px. */
h1, h2, h3 {
  margin: 0 0 0.5em;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.01em;
  text-wrap: balance;
}
h1 { font-size: clamp(30px, 4.4vw, 46px); letter-spacing: -0.022em; }
h2 { font-size: clamp(21px, 2.2vw, 27px); letter-spacing: -0.018em; }
h3 { font-size: 17px; letter-spacing: -0.01em; }

/* Rank 4 — the label above a group of fields or values. Not a heading: no weight contest with
   h3, it works by being small, wide and quiet. */
.label {
  margin: 0 0 8px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
}

p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }

/* The sentence under a title. Larger than body, lighter than text — it belongs to the heading,
   not to the paragraphs after it. */
.lead {
  max-width: 58ch;
  color: var(--muted);
  font-size: clamp(16px, 1.5vw, 18px);
  line-height: 1.55;
  text-wrap: pretty;
}

/* Figures are tabular wherever they sit in a column, per the handoff. */
.num { font-variant-numeric: tabular-nums; }

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 20px;
}
.wrap--narrow { max-width: 720px; }

.muted { color: var(--muted); }
.small { font-size: 13px; }

/* ── Sections ───────────────────────────────────────────────────────────────────────────── */
/* The one structural addition the templates need. A page is a sequence of <section class="sec">,
   and the rhythm comes from the sequence rather than from a lone <hr>: consecutive sections are
   separated by a hairline, and the first one after the header is not. Add `sec--plain` where a
   section continues the previous thought and the line would over-divide it. */
.sec { padding: var(--sp-sec) 0; }
.sec + .sec { border-top: 1px solid var(--line); }
.sec + .sec--plain { border-top: 0; padding-top: 0; }
.sec--tight { padding: calc(var(--sp-sec) * 0.55) 0; }

/* The header of a section: kicker, title, one sentence. Kept as a unit so the gap below it is
   the same everywhere and never collapses into the content. */
.sec__head { margin-bottom: var(--sp-block); }
.sec__head > * { margin-bottom: 0; }
.sec__head > * + * { margin-top: 8px; }

/* Title on the left, a link or count on the right, baselines aligned. */
.sec__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 16px;
  margin-bottom: var(--sp-block);
}
.sec__bar h2 { margin: 0; }
.sec__bar .sec__aside { margin-left: auto; font-size: 14px; }

/* Page opening. The h1 and its lead, with room above so the title is not welded to the header
   bar, and nothing else competing inside it. */
.page-head { padding: clamp(32px, 5vw, 56px) 0 0; }
.page-head h1 { margin-bottom: 12px; }

/* Breadcrumb-ish back link, above the title. */
.backlink {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 18px;
  color: var(--muted);
  font-size: 14px;
  font-weight: 500;
}
.backlink:hover { color: var(--text); text-decoration: none; }

/* A generic vertical stack for the places where blocks just follow each other. Replaces the
   default margin soup: one gap value, set here, instead of every element's own bottom margin. */
.stack { display: flex; flex-direction: column; gap: var(--sp-block); }
.stack--sm { gap: 12px; }
.stack--lg { gap: calc(var(--sp-block) * 1.5); }

/* ── Header ─────────────────────────────────────────────────────────────────────────────── */
/* The Mini App has no header — Telegram draws one. This is site-only, built from the same
   tokens: the gradient logo mark, then nav, then the locale switcher. */
.hdr {
  position: sticky;
  top: 0;
  z-index: 10;
  /* Opaque first: where color-mix is unsupported the declaration is dropped, and without a
     fallback the header would sit transparent over scrolling content. */
  background: var(--bg);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}

.hdr__in {
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 60px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--text);
  font-weight: 700;
  font-size: 16px;
  letter-spacing: -0.01em;
}
.brand:hover { text-decoration: none; }

/* The mark carries the brand gradient itself, so no plate and no glow behind it — and it
   reads on both schemes, which is why the transparent version is used rather than the one
   with a dark backing. */
.brand__mark { width: 34px; height: 34px; flex: 0 0 auto; }

.nav {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-left: auto;
}

.nav__link {
  padding: 8px 12px;
  border-radius: var(--r-btn);
  color: var(--text);
  font-size: 14px;
  font-weight: 500;
  /* A link is one word or two, never one and a half: "All games" wrapped mid-phrase on a phone
     and pushed the row into two ragged lines. Nothing here is long enough for wrapping to buy
     space. */
  white-space: nowrap;
}
.nav__link:hover { background: var(--chip); text-decoration: none; }
.nav__link[aria-current='page'] { color: var(--accent-violet); }

/* Locale switcher — a <details> dropdown, so it costs the width of one label instead of three.
   The element opens, closes and takes keyboard focus by itself; the only script on the site
   closes it on an outside click, which <details> has no concept of. */
.langs { position: relative; }

/* Same shape as .nav__link on purpose. Choosing a language is not an action anyone came here
   to perform, so it must not out-shout the navigation next to it: no border, no standing
   background, colour only on hover or while open. */
.langs__now {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  border-radius: var(--r-btn);
  color: var(--muted);
  font-size: 14px;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  user-select: none;
  /* The default triangle would sit beside our own chevron. */
  list-style: none;
}
.langs__now::-webkit-details-marker { display: none; }
.langs__now:hover,
.langs[open] .langs__now { color: var(--text); background: var(--chip); }

.langs__chev { opacity: 0.55; transition: transform 0.15s ease; }
.langs[open] .langs__chev { transform: rotate(180deg); }

.langs__menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  min-width: 132px;
  padding: 5px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surf);
  box-shadow: 0 8px 20px rgb(0 0 0 / 0.1);
}

.langs__item {
  padding: 7px 9px;
  border-radius: 8px;
  color: var(--text);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.2;
  white-space: nowrap;
}
.langs__item:hover { background: var(--chip); text-decoration: none; }
/* Accent text, not an accent-filled row: in a list of three, "you are here" needs to be
   readable, not announced. */
.langs__item[aria-current='true'] {
  color: var(--accent-violet);
  font-weight: 600;
}

/* ── Buttons ────────────────────────────────────────────────────────────────────────────── */
/* One transparent border on the base class, so the outline variants can colour it without
   changing the box: previously .btn set `border: 0` and .btn--danger only set border-color,
   which meant the red outline it was supposed to have never actually drew. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 12px 22px;
  border: 1px solid transparent;
  border-radius: var(--r-btn);
  background: transparent;
  color: var(--text);
  font: 600 15px/1 'Inter', system-ui, sans-serif;
  text-align: center;
  cursor: pointer;
  transition: filter 0.15s, background-color 0.15s, border-color 0.15s, color 0.15s;
}
.btn:hover { text-decoration: none; }
.btn:focus-visible { outline: 2px solid var(--accent-violet); outline-offset: 2px; }

.btn--primary {
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: var(--glow);
}
.btn--primary:hover { filter: brightness(1.06); }
.btn--primary:active { transform: translateY(1px); }

/* The everyday second button: sign out, keep this device, cancel. Visible, never loud. */
.btn--ghost {
  border-color: var(--chipline);
  background: var(--surf);
  color: var(--text);
}
.btn--ghost:hover { background: var(--chip); border-color: var(--muted); }

.btn--lg { min-height: 50px; padding: 15px 28px; font-size: 16px; }
.btn--block { display: flex; width: 100%; }

/* Deleting an account looked exactly like keeping a save: same pill, same weight, sitting a
   thumb apart on the same screen. A destructive action has to say so before it is pressed —
   the confirm dialog is the second line of defence, not the first. Kept as an outline rather
   than a filled red button: it must be recognisable, not attractive. */
.btn--danger {
  border-color: color-mix(in srgb, var(--danger) 55%, transparent);
  color: var(--danger-ink);
}
.btn--danger:hover {
  background: color-mix(in srgb, var(--danger) 12%, transparent);
  border-color: var(--danger);
}
.btn--danger:focus-visible { outline-color: var(--danger); }

/* The one alignment rule for buttons on a page. Everything that is a row of buttons uses it,
   so a screen never shows two strategies at once — before, "Sign out" and "Delete account" sat
   narrow on the left while the two choice buttons sat paired in the middle. */
.btnrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}
.btnrow--spread { justify-content: space-between; }
/* Phones: full width and stacked, in the order written. */
@media (max-width: 519px) {
  .btnrow > .btn { flex: 1 1 100%; }
}

/* ── Badges ─────────────────────────────────────────────────────────────────────────────── */
.badge {
  display: inline-block;
  padding: 3px 8px;
  border-radius: 6px;
  background: rgba(124, 92, 255, 0.16);
  color: var(--accent-violet);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  vertical-align: middle;
}

/* Neutral counterpart — a category, a count, a state. Same shape, no claim on attention. */
.badge--quiet {
  background: var(--chip);
  border: 1px solid var(--chipline);
  color: var(--muted);
  font-weight: 600;
}

.kicker {
  display: block;
  color: var(--accent-violet);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* ── Game grid and cards ────────────────────────────────────────────────────────────────── */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 18px;
}

.card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--surf);
  color: var(--text);
  transition: transform 0.15s, box-shadow 0.15s, border-color 0.15s;
}
.card:hover {
  text-decoration: none;
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--accent-violet) 40%, var(--line));
  box-shadow: 0 12px 30px rgba(124, 92, 255, 0.18);
}

.card__art { aspect-ratio: 315 / 250; width: 100%; object-fit: cover; }
.card__body { display: flex; flex-direction: column; gap: 4px; padding: 14px 16px 16px; }

/* Title and beta on one line, the badge riding the title's baseline rather than pushing the
   line height around. */
.card__title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  line-height: 1.25;
}
.card__sub { margin: 0; color: var(--muted); font-size: 14px; line-height: 1.45; }
/* Category sits last and smallest: it is how you scan a grid, not why you click a card. */
.card__cat {
  margin-top: 6px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* ── Empty state ────────────────────────────────────────────────────────────────────────── */
/* A new locale has no games at all. An empty page must still look built, and must offer the
   way out — the games do exist, in another language. */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: clamp(40px, 7vw, 72px) 24px;
  border: 1px dashed var(--chipline);
  border-radius: var(--r-card);
  text-align: center;
}
.empty h2 { margin: 0; font-size: 20px; }
.empty p { max-width: 42ch; margin: 0; color: var(--muted); }

/* ── Game page ──────────────────────────────────────────────────────────────────────────── */
.hero {
  display: grid;
  gap: 28px;
  align-items: start;
  margin: 32px 0;
}
@media (min-width: 760px) {
  .hero { grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); }
}

.hero__art {
  width: 100%;
  border: 1px solid var(--line);
  border-radius: 22px;
  box-shadow: 0 12px 30px rgba(124, 92, 255, 0.18);
}

/* Right column of the hero: category, title, one line, the button, the caveat under it. */
.hero__body { display: flex; flex-direction: column; gap: 14px; }
.hero__body h1 { margin: 0; }
.hero__title { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
.hero__note { margin: 0; color: var(--muted); font-size: 13px; }

.cols { display: grid; gap: 28px; }
/* Grid items stretch by default, so a short side panel drew an empty box as tall as the
   column beside it. Panels are as tall as what is in them. */
.cols > * { align-self: start; }
@media (min-width: 760px) {
  .cols { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); }
}

.panel {
  padding: 18px;
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--surf);
}
.panel--pad { padding: clamp(18px, 3vw, 26px); }

/* A label/value pair inside a panel — "Scored by: Time". This is the bold line that used to
   look like a third heading; it is data, so it is set as data. */
.kv { display: flex; flex-direction: column; gap: 2px; }
.kv + .kv { margin-top: 14px; }
.kv__k {
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
}
.kv__v { font-size: 16px; font-weight: 600; }

.steps { margin: 0; padding: 0; list-style: none; counter-reset: step; }
.steps li {
  display: grid;
  grid-template-columns: 26px 1fr;
  gap: 12px;
  margin-bottom: 12px;
  font-size: 15px;
}
.steps li:last-child { margin-bottom: 0; }
.steps li::before {
  counter-increment: step;
  content: counter(step);
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 8px;
  background: rgba(124, 92, 255, 0.15);
  color: var(--accent-violet);
  font-size: 13px;
  font-weight: 700;
}

.shots { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; }
.shots img { border: 1px solid var(--line); border-radius: 12px; }

/* ── Forms ──────────────────────────────────────────────────────────────────────────────── */
/* Symfony's plain div layout, styled here. Bootstrap's form theme went with Bootstrap. */
.form { max-width: 520px; }

.form label {
  display: block;
  margin-bottom: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
}

.form input[type='text'],
.form input[type='email'],
.form textarea {
  width: 100%;
  margin-bottom: 18px;
  padding: 12px 14px;
  border: 1px solid var(--chipline);
  border-radius: var(--r-btn);
  background: var(--surf);
  color: var(--text);
  font: 400 15px/1.5 'Inter', system-ui, sans-serif;
}
.form textarea { min-height: 140px; resize: vertical; }

.form input:focus-visible,
.form textarea:focus-visible {
  outline: 2px solid var(--accent-violet);
  outline-offset: 1px;
}

.form button {
  min-height: 44px;
  padding: 12px 22px;
  border: 0;
  border-radius: var(--r-btn);
  background: var(--accent);
  color: var(--on-accent);
  font: 600 15px/1 'Inter', system-ui, sans-serif;
  box-shadow: var(--glow);
  cursor: pointer;
}
.form button:hover { filter: brightness(1.06); }

/* Validation messages — Symfony renders them as a ul before the field. */
.form ul {
  margin: 0 0 8px;
  padding-left: 18px;
  color: #ff6b8a;
  font-size: 13px;
}

/* A note that belongs to the control right above it. It has to be *inside* that block in the
   markup, not floating between two blocks — the privacy line on the account page sat between
   the choice buttons and "Sign out" and read as belonging to whichever one you looked at. */
.note {
  margin: 0;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}
.note--tight { margin-top: -6px; }

/* ── Callouts ───────────────────────────────────────────────────────────────────────────── */
/* Confirmation after a form is sent, and after an account is deleted. Same object, two tones. */
.callout {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: clamp(18px, 3vw, 26px);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--surf);
}
.callout h2 { margin: 0; font-size: 20px; }
.callout p { margin: 0; color: var(--muted); }
.callout .btnrow { margin-top: 6px; }

/* ── Account ────────────────────────────────────────────────────────────────────────────── */
/* Signed in, and one row per save. A save is four facts about one game, so it is one object
   with a border around it, not four consecutive paragraphs. */
.save {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--surf);
}
.save__art {
  width: 52px;
  height: 52px;
  flex: 0 0 auto;
  border-radius: 10px;
  object-fit: cover;
}
.save__body { min-width: 0; }
.save__name { margin: 0; font-size: 15px; font-weight: 700; }
.save__val { margin: 0; color: var(--muted); font-size: 14px; }
.save__when { margin-left: auto; flex: 0 0 auto; color: var(--muted); font-size: 12px; }
@media (max-width: 519px) {
  .save { flex-wrap: wrap; }
  .save__when { margin-left: 66px; }
}

/* The conflict. This is the most consequential thing on the site and it was set as body text.
   It gets: its own card, a two-point ring in the brand violet so it is the only ringed thing
   on the page, a kicker that names it as a question, and — the part that actually does the
   work — the two answers as two columns with their button at the foot of each. The button is
   inside the option it chooses, so "which one does this apply to" is never a question. */
.conflict {
  border: 2px solid color-mix(in srgb, var(--accent-violet) 45%, transparent);
  border-radius: var(--r-card);
  background: var(--surf);
  box-shadow: var(--shadow-card);
}
.conflict__head { padding: clamp(18px, 3vw, 24px) clamp(18px, 3vw, 24px) 0; }
.conflict__head .kicker { margin-bottom: 8px; }
.conflict__title { margin: 0; font-size: clamp(18px, 2vw, 21px); }
.conflict__head .note { margin-top: 8px; }

.conflict__opts {
  display: grid;
  gap: 1px;
  padding: clamp(18px, 3vw, 24px);
  /* The hairline between the two columns is the grid gap showing through. */
  background: transparent;
}
@media (min-width: 620px) {
  .conflict__opts { grid-template-columns: 1fr 1fr; gap: clamp(18px, 3vw, 24px); }
  .conflict__opt + .conflict__opt {
    padding-left: clamp(18px, 3vw, 24px);
    border-left: 1px solid var(--line);
  }
}
@media (max-width: 619px) {
  .conflict__opts { gap: 16px; }
  .conflict__opt + .conflict__opt { padding-top: 16px; border-top: 1px solid var(--line); }
}

.conflict__opt { display: flex; flex-direction: column; gap: 6px; }
.conflict__where {
  margin: 0;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
}
.conflict__val {
  margin: 0;
  font-size: clamp(17px, 2vw, 19px);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.3;
}
.conflict__when { margin: 0; color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }
/* Both buttons land on the same line even when one column is a line taller than the other:
   the two options already stretch to equal height, and `margin-top: auto` inside a flex
   column pushes the button to the foot of each. Nothing may set a margin-top on the button —
   that cancels the `auto`; the breathing room above comes from the line before it instead. */
.conflict__opt > .btn { margin-top: auto; width: 100%; }
.conflict__val:has(+ .btn),
.conflict__when:has(+ .btn) { margin-bottom: 8px; }

/* The result of the choice, at the foot of the card the choice was made in. A status line in
   the card's header sits above four lines of content and two buttons — the eye is at the
   buttons when it is pressed, and that is where the answer has to appear. Full width, its own
   band, so it reads as the card's reply rather than as one more thing to decide.
   Mark it up as <p class="conflict__status" role="status"> so it is announced when it
   changes; on failure add `conflict__status--fail`. */
.conflict__status {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 12px clamp(18px, 3vw, 24px);
  border-top: 1px solid var(--line);
  border-radius: 0 0 calc(var(--r-card) - 2px) calc(var(--r-card) - 2px);
  background: var(--surf-2);
  color: var(--text);
  font-size: 13px;
  font-weight: 600;
}
.conflict__status--fail {
  background: color-mix(in srgb, var(--danger) 9%, var(--surf-2));
  color: var(--danger-ink);
}
/* When a status band is present the options above it no longer need their own bottom padding. */
.conflict__opts:has(+ .conflict__status) { padding-bottom: clamp(14px, 2.4vw, 18px); }

/* The value the game itself sends back. It arrives in whatever language the player was
   playing in, and we neither translate it nor can. Rather than let a Ukrainian line sit
   unexplained on a Russian page, the line is marked as a quotation of the game: quiet
   monospace-tabular figures stay, plus a small tag after it. Set lang= on the element so a
   screen reader switches voice instead of reading Cyrillic through an English one. */
.foreign {
  display: inline-flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
}
.foreign__tag {
  padding: 2px 7px;
  border: 1px solid var(--chipline);
  border-radius: 6px;
  background: var(--chip);
  color: var(--muted);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}
/* Inline beside a 14px muted line in the saves list, but stacked under the big bold value in
   the conflict: at 19px/700 a 10px chip on the same baseline reads as part of the figure. */
.conflict__val .foreign {
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}

/* Sign-in: one button, and nothing else will ever be added. It is centred and given air
   because a page with a single action should look like one, not like an unfinished form. */
.signin {
  max-width: 420px;
  margin: clamp(32px, 8vw, 80px) auto;
  padding: clamp(24px, 4vw, 32px);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--surf);
  box-shadow: var(--shadow-card);
  text-align: center;
}
.signin h1 { font-size: clamp(24px, 3vw, 30px); margin-bottom: 10px; }
.signin .lead { margin: 0 auto 22px; font-size: 15px; }
.signin .btn { width: 100%; }
.signin .note { margin-top: 14px; }

/* The irreversible corner. Held apart from everything else by distance and a hairline, at the
   very bottom of the page, with its explanation attached to it rather than to the block above. */
.danger-zone {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 20px;
  margin-top: calc(var(--sp-sec) * 0.6);
  padding-top: 22px;
  border-top: 1px solid var(--line);
}
.danger-zone .note { flex: 1 1 280px; }
.danger-zone .btn { margin-left: auto; }
@media (max-width: 519px) {
  .danger-zone .btn { margin-left: 0; width: 100%; }
}

/* ── Footer ─────────────────────────────────────────────────────────────────────────────── */
.ftr {
  margin-top: var(--sp-sec);
  padding: 28px 0;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 13px;
}
.ftr__in { display: flex; flex-wrap: wrap; gap: 12px 20px; align-items: center; }
.ftr a { color: var(--muted); }
.ftr a:hover { color: var(--text); }

/* ── Motion ─────────────────────────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
  .card:hover { transform: none; }
}

/* Sign-in gained a second door. The rules above assumed one button and said so; both the
   assumption and the comment are now false, and this block is the correction rather than an
   override — the width rule still holds, it just applies to two things instead of one. */
.signin__or {
    margin: 14px 0 10px;
    color: var(--muted);
    font-size: 13px;
    text-align: center;
    text-transform: lowercase;
}
.btn--google {
    display: inline-flex;
    gap: 10px;
    align-items: center;
    justify-content: center;
    width: 100%;
    background: #fff;
    border: 1px solid #dadce0;
    color: #1f1f1f;
    font-weight: 600;
}
.btn--google:hover { background: #f7f8f8; }
.btn__mark { flex: 0 0 auto; }
.signin__error { color: var(--danger, #c2410c); }

/* The store link under a game's Play button. Reuses .btn/.btn--ghost; the only new rules are
   the row, the note beside it, and the one that hides the whole thing inside our own Android
   app — see the snippet in base.html.twig for how that class arrives. */
.storelink {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin: 18px 0 0;
}
.storelink__note { color: var(--muted); font-size: 0.92rem; }
.cg-host-android .storelink { display: none; }
