/* Page shell: reset, body/main, the header row, and the footer strip
   (sound toggle). Everything here is chrome around the game
   rather than part of any one mode or component. */

* { box-sizing: border-box; }

/* ── Scrollbars ────────────────────────────────────────────────────────────
   One design everywhere something scrolls — the page itself, the inventory
   grid, the comparison table wrapper — rather than each container styling
   its own. Firefox and Chromium don't share a scrollbar-styling API, so both
   are set: scrollbar-width/-color for Firefox, ::-webkit-scrollbar for
   Chromium and Safari. A transparent track is what makes one rule work over
   every container's background instead of needing a matching colour per
   context. */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}
::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
::-webkit-scrollbar-track {
  background: transparent;
}
::-webkit-scrollbar-thumb {
  background-color: var(--border-strong);
  /* Clipped to the padding box behind a transparent border: shrinks the
     visible thumb off the track's edges without narrowing the actual
     (harder-to-hit) scroll track underneath it. */
  background-clip: padding-box;
  border: 2px solid transparent;
  border-radius: var(--radius-lg);
}
::-webkit-scrollbar-thumb:hover {
  background-color: var(--text-faint);
}
::-webkit-scrollbar-corner {
  background: transparent;
}
/* The stepper buttons at each end of a scrollbar track. Chromium omits them
   by default, but zeroing them explicitly rather than relying on that means
   the design holds anywhere it doesn't. */
::-webkit-scrollbar-button {
  display: none;
  width: 0;
  height: 0;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: 'Inter', sans-serif;
  /* The UA default (~1.2) is display leading applied to prose. The status line
     and the answer's title routinely wrap to two lines, and at 1.2 those lines
     sit close enough to read as one block. Controls opt back out to 1.2
     individually — leading is for running text, not for labels centred in a
     box. */
  line-height: var(--leading-normal);
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}

/* --content-max (1260px) — the game's original width. */
main {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 56px 4vw 90px;
}

/* Scrolls away with the page rather than following it down. It was sticky for a
   while, on the reasoning that the streak and sound toggle were worth keeping
   reachable from the bottom of a long page; in practice it spent that screen
   space on every scroll of every page. Nothing passes under it now, so the
   translucent material and its backdrop-filter went with the stickiness.

   A sibling of <main> in the markup, not a child of it — main is capped at
   1260px, so a background/border nested inside main can only ever bleed out
   to main's own padding gutters, not the true viewport edge. On any screen
   wider than ~1260px + gutters that left a visible gap on both sides (the
   "line stops short" bug) instead of a border that reaches the edges. Being
   a sibling means this element's own box IS the viewport width, so the
   border genuinely goes edge to edge. */
.top-row {
  border-bottom: 1px solid var(--border);
  background: var(--bg);
}

/* Mirrors main's own max-width/centering so the header's *content* — title,
   streak, buttons — still lines up with the game column below it, even
   though .top-row's background now spans past it on both sides. */
.top-row-inner {
  max-width: var(--content-max);
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding: 16px 4vw;
}

/* The site name, on every page. Deliberately NOT an <h1>: the brand is chrome,
   and each page's <h1> belongs to that page's own subject — "Pixel: Splash" on the
   pixel page, "About" on the about page. When this was an h1 the informational
   pages carried two of them and every mode page announced itself by the site
   name rather than by the mode, which is the heading a search result leads with.
   A link rather than plain text, so the wordmark is the way back to the home
   page — the convention everywhere else on the web. */
.top-row .brand {
  display: inline-block;
  font-family: 'Rajdhani', sans-serif;
  /* Fluid, so the title scales with the viewport instead of stepping once at
     640px. Replaces the old fixed 1.8rem and the mobile override that went
     with it. */
  /* The one fluid size on the page, and the only one that interpolates rather
     than picking a step: a title that stepped at a breakpoint would jump. The
     endpoints are scale steps even so, so it ramps between two sizes the rest
     of the page also uses instead of between two numbers of its own. */
  font-size: clamp(var(--text-xl), 1.1rem + 1.4vw, var(--text-3xl));
  font-weight: 700;
  line-height: var(--leading-tight);
  color: var(--text);
  text-decoration: none;
  /* Eased down from 0.04em. Large type normally wants tighter tracking as it
     grows, but the usual rule inverts for uppercase — caps need some positive
     tracking to stay readable — so this lands short of zero rather than past
     it. */
  letter-spacing: var(--tracking-caps-lg);
  text-transform: uppercase;
  margin: 0;
  transition: color var(--dur-ui) var(--ease-out);
}
.top-row .brand:hover { color: var(--accent); }
.top-row .brand:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-sm);
}

/* Wordmark and mode badge on one line. */
.brand-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

/* Which mode you are actually playing, named beside the wordmark — which is
   otherwise identical on all four pages.

   Outlined rather than filled: the active tab is the filled accent element, and
   two solid accent blocks would compete instead of reading as heading and
   sub-heading. */
.mode-badge {
  font-family: 'Rajdhani', sans-serif;
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-caps-sm);
  text-transform: uppercase;
  color: var(--accent);
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  padding: 4px 9px;
  line-height: var(--leading-none);
  white-space: nowrap;
}

.top-row .subtitle {
  color: var(--text-faint);
  font-size: var(--text-sm);
  font-weight: 500;
  margin-top: 4px;
}

/* Right-hand cluster of the header: streak + sound toggle */
.top-row-right {
  display: flex;
  align-items: center;
  gap: 14px;
}

/* Streak badge */
#streak {
  color: var(--text-muted);
  font-family: 'Rajdhani', sans-serif;
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: var(--tracking-caps-sm);
  white-space: nowrap;
}

button {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: var(--text-md);
  letter-spacing: var(--tracking-caps-sm);
  text-transform: uppercase;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  padding: 11px 22px;
  /* Leading pinned here rather than inherited: body carries prose leading
     (1.5), which would silently make every control ~6px taller. */
  line-height: var(--leading-snug);
  /* No grey flash on tap, and no 300ms wait while the browser rules out a
     double-tap — the press squash below is the feedback, and it can't read as
     immediate if the browser spends a third of a second deciding. */
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background var(--dur-ui) var(--ease-out),
              border-color var(--dur-ui) var(--ease-out),
              color var(--dur-ui) var(--ease-out),
              scale var(--dur-press) var(--ease-out),
              transform var(--dur-press) var(--ease-out);
  background: var(--accent);
  color: #FFFFFF;
}
button:hover { background: var(--accent-hover); }
button:disabled { opacity: 0.35; cursor: not-allowed; }

/* Feedback on press, not on release. The colour change already happens on
   hover, which a touch device never sees — this is the only signal that the
   button took the input, so it fires on pointer-down.

   The independent `scale` property rather than transform: scale(). transform is
   a single slot, so a control that already uses it for something else — the
   inventory tile's hover lift — had that lift *replaced* by the squash, and the
   tile dropped 2px at the moment it was pressed. scale and transform compose,
   so hover and press can both hold their own state. */
button:active:not(:disabled) { scale: 0.97; }

/* Keyboard focus was previously whatever the browser defaulted to, which on a
   dark background against these borders was close to invisible. :where() keeps
   the specificity at zero so any component can still style its own focus. */
:where(button, input, a, [tabindex]):focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* ── Language switcher ──────────────────────────────────────────────────
   A <details> wrapping real <a> links, one per language, each pointing at THIS
   page in that language. Not a <select>: the whole point of giving every
   language its own URL is that a crawler can follow it, and a select's options
   are not links. It also means the control works with no JS at all.

   There is deliberately no automatic redirect by Accept-Language anywhere in
   the site. Google crawls from one country and would only ever see one
   language, and a reader who has chosen a language should not have it
   overridden by their browser's header. tools/i18n-render.js carries the same
   note. */
.lang-switcher {
  position: relative;
  flex-shrink: 0;
}

/* Styled like #soundBtn below: both are header chrome rather than game
   controls, and they sit next to each other. */
.lang-current {
  font-family: 'Rajdhani', sans-serif;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: var(--tracking-caps-sm);
  text-transform: uppercase;
  line-height: var(--leading-snug);
  color: var(--text-muted);
  background: transparent;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 6px 10px;
  cursor: pointer;
  white-space: nowrap;
  /* The disclosure triangle is a UA glyph that differs per browser and cannot
     be styled; the caret below is ours. */
  list-style: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: border-color var(--dur-ui) var(--ease-out),
              color var(--dur-ui) var(--ease-out);
}
.lang-current::-webkit-details-marker { display: none; }
.lang-current::after {
  content: " \25BE";
  color: var(--accent);
}
.lang-current:hover {
  color: var(--text);
  border-color: var(--accent);
}
.lang-switcher[open] .lang-current {
  color: var(--text);
  border-color: var(--accent);
}

/* Anchored to the INLINE END of the header, which is the right edge in English
   and the left edge in Arabic — either way the edge the switcher itself sits on,
   so the list grows inward and stays on screen. inset-inline-end rather than
   right for exactly that reason: under dir="rtl" a hardcoded `right` would pin
   the list to the far side of the header from the control that opened it. */
.lang-list {
  position: absolute;
  top: calc(100% + 6px);
  inset-inline-end: 0;
  z-index: 40;
  margin: 0;
  padding: 4px;
  list-style: none;
  min-width: 100%;
  max-height: 60vh;
  overflow-y: auto;
  background: var(--surface-raised);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
}

.lang-list a {
  display: block;
  padding: 8px 14px;
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  color: var(--text-muted);
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--dur-ui) var(--ease-out),
              color var(--dur-ui) var(--ease-out);
}
.lang-list a:hover {
  background: var(--surface-hover);
  color: var(--text);
}
/* The language you are already reading. aria-current is the source of truth
   here rather than a class, so the styling cannot drift from what a screen
   reader announces. */
.lang-list a[aria-current="true"] {
  color: var(--accent);
  font-weight: 600;
}

/* flag-icons artwork, MIT — see static/flags/LICENSE. */
.flag {
  margin-inline-end: 8px;
  vertical-align: -2px;
  border-radius: 2px;
  /* White-edged flags (JP, PL, ID) would otherwise dissolve into the panel
     behind them, which is near-white in light mode. */
  box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.2);
}

/* Icon-sized and quiet: chrome, not a game control. */
#soundBtn {
  font-size: var(--text-sm);
  line-height: var(--leading-none);
  padding: 6px 10px;
  background: transparent;
  border: 1px solid var(--border-strong);
  color: var(--text-muted);
}
#soundBtn:hover {
  border-color: var(--text-muted);
  background: transparent;
}

@media (max-width: 640px) {
    main {
      padding: 32px 4vw 60px;
    }

    /* Compact on phones: dropping the subtitle and keeping the right-hand
       cluster inline collapses what would otherwise be a two-row header. */
    .top-row-inner {
      padding: 10px 4vw;
      gap: 10px;
      flex-wrap: nowrap;
    }

    /* Prose, and the first thing to go when the bar has to earn its height —
       the mode badge beside the wordmark says more in less room. */
    .top-row .subtitle {
      display: none;
    }

    .top-row-right {
      gap: 10px;
      flex-shrink: 0;
    }

    /* The bar is nowrap from here down and "Español (Latinoamérica)" ran off
       a 360px phone. Hidden, not removed: a <summary> with no text has no
       accessible name. */
    .lang-current .lang-name {
      position: absolute;
      width: 1px;
      height: 1px;
      overflow: hidden;
      clip-path: inset(50%);
      white-space: nowrap;
    }

    .lang-current .flag {
      margin-inline-end: 2px;
    }
}

/* ── User preferences ───────────────────────────────────────────────────── */

@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;
  }
  /* The press squash is motion rather than a state change, so it goes
     entirely — the colour change still confirms the press. */
  button:active:not(:disabled) { scale: 1; }
}

/* The prefers-reduced-transparency block that lived here is gone with the
   header's translucency: nothing on the page uses a backdrop-filter any more,
   so there was no transparency left for it to reduce. */

@media (prefers-contrast: more) {
  :root {
    --border: #4A4A4A;
    --border-strong: #6E6E6E;
    --text-muted: #B4B4B4;
    --text-faint: #909090;
  }
}
