@font-face {
  font-family: 'system';
  src: local('Segoe UI');
}

/* Self-hosted Roboto (was Google Fonts — see index.html's removed
   preconnect/stylesheet links) — mirrors exactly what fonts.googleapis.com
   itself served for `family=Roboto:wght@400;600;700&display=swap`, just
   fetched once into vendor/fonts/roboto/ instead of requested live. Only
   the latin and latin-ext subsets: this site is Polish-only content plus
   the odd English abbreviation (UX/UI, ROOTS), so the other seven subsets
   Google normally ships (cyrillic, greek, vietnamese, symbols, math, ...)
   would be dead weight here. Roboto's current build is a variable font, so
   all three weights below point at the same two files — the browser reads
   each declared font-weight off the file's own weight axis, same as it
   would from Google's CDN. */
@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('./vendor/fonts/roboto/roboto-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: 'Roboto';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('./vendor/fonts/roboto/roboto-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: 'Roboto';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('./vendor/fonts/roboto/roboto-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: 'Roboto';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('./vendor/fonts/roboto/roboto-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: 'Roboto';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('./vendor/fonts/roboto/roboto-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: 'Roboto';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('./vendor/fonts/roboto/roboto-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;
}

:root {
  --font: 'Roboto', -apple-system, 'Segoe UI', 'Inter', Arial, sans-serif;
  color-scheme: dark light;
}

/* ---------- Dark theme (default) ---------- */
body[data-theme="dark"] {
  --bg-0: #060710;
  --bg-1: #0b0e18;
  --bg-2: #161327;
  --surface: rgba(18, 20, 32, 0.55);
  --border: rgba(255, 255, 255, 0.14);
  --text: #eef0f7;
  --text-dim: #9aa0ba;
  --accent-1: #7dd3fc;
  --accent-2: #c084fc;
  --accent-3: #f472b6;
  --shadow: 0 24px 70px rgba(0, 0, 0, 0.6);
  --kbd-bg: rgba(255, 255, 255, 0.08);
}

/* ---------- Light theme ---------- */
body[data-theme="light"] {
  --bg-0: #f4f2ec;
  --bg-1: #fbfaf6;
  --bg-2: #e7e1d3;
  --surface: rgba(255, 255, 255, 0.6);
  --border: rgba(20, 18, 10, 0.12);
  --text: #171712;
  --text-dim: #5c5a4e;
  --accent-1: #0891b2;
  --accent-2: #7c3aed;
  --accent-3: #db2777;
  --shadow: 0 24px 70px rgba(30, 25, 10, 0.18);
  --kbd-bg: rgba(0, 0, 0, 0.06);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  font-family: var(--font);
  background: var(--bg-0);
  color: var(--text);
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior: none;
}

body {
  transition: background-color .6s ease, color .6s ease;
}

#scene {
  position: fixed;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  touch-action: none;
}

.vignette {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 2;
  background:
    radial-gradient(ellipse at center, transparent 45%, var(--bg-0) 130%);
  opacity: .9;
  transition: background-color .6s ease;
}

/* ---------- Accessible fallback content ---------- */
/* Real name/bio/links markup (see index.html) that screen readers, search
   engines, and no-JS/no-WebGL visitors rely on instead of the canvas-only
   scene — clipped to nothing by default so sighted mouse/touch visitors
   (who already get the real experience) never see it, but still reachable
   by keyboard: focusing a link inside pops the whole block into view as a
   small panel, the standard "skip navigation" pattern, rather than leaving
   a sighted keyboard user tabbing onto something invisible. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.sr-only:focus-within {
  z-index: 999;
  position: fixed;
  top: 12px;
  left: 12px;
  width: auto;
  height: auto;
  padding: 16px 20px;
  margin: 0;
  overflow: visible;
  clip: auto;
  white-space: normal;
  max-width: min(420px, 90vw);
  background: var(--bg-1);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow);
}
.sr-only h1 { font-size: 15px; margin: 0 0 8px; }
.sr-only p { font-size: 13px; color: var(--text-dim); margin: 0 0 12px; }
.sr-only nav ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.sr-only nav a { color: var(--accent-1); font-size: 13px; }

/* ---------- Loading indicator ---------- */
.loading {
  position: fixed;
  inset: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-0);
  transition: opacity .4s ease;
}
.loading.hidden {
  opacity: 0;
  pointer-events: none;
}
.loading-spinner {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 3px solid var(--border);
  border-top-color: var(--accent-1);
  animation: loading-spin 0.9s linear infinite;
}
@keyframes loading-spin {
  to { transform: rotate(360deg); }
}

/* ---------- Topbar ---------- */
.topbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: clamp(14px, 3vw, 28px) clamp(16px, 4vw, 36px);
  pointer-events: none;
}

.brand {
  display: flex;
  align-items: center;
  gap: .6em;
  pointer-events: auto;
  opacity: .92;
}

.brand-mark svg {
  width: 26px;
  height: 26px;
  fill: none;
  stroke: var(--accent-1);
  stroke-width: 6;
  filter: drop-shadow(0 0 6px color-mix(in srgb, var(--accent-1) 60%, transparent));
}

.brand-name {
  font-size: 14px;
  letter-spacing: .04em;
  font-weight: 600;
  color: var(--text-dim);
}

.theme-toggle {
  pointer-events: auto;
  position: fixed;
  left: clamp(16px, 4vw, 36px);
  bottom: clamp(14px, 3vh, 26px);
  z-index: 10;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  display: grid;
  place-items: center;
  cursor: pointer;
  color: var(--text);
  box-shadow: var(--shadow);
  transition: transform .25s ease, background-color .4s ease, border-color .4s ease;
}
.theme-toggle:hover { transform: translateY(-1px) scale(1.04); }
.theme-toggle:active { transform: scale(.96); }
.theme-toggle svg {
  position: absolute;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: opacity .35s ease, transform .5s ease;
}
.icon-sun circle { fill: currentColor; stroke: none; }
body[data-theme="dark"] .icon-sun { opacity: 0; transform: rotate(90deg) scale(.5); }
body[data-theme="dark"] .icon-moon { opacity: 1; transform: rotate(0) scale(1); }
body[data-theme="light"] .icon-moon { opacity: 0; transform: rotate(-90deg) scale(.5); }
body[data-theme="light"] .icon-sun { opacity: 1; transform: rotate(0) scale(1); }

/* ---------- Language switch ---------- */
/* Mirrors .theme-toggle's own fixed bottom-left placement onto the opposite
   corner — same clamp() values, so both sit at the same height regardless
   of viewport size. Just a link to the sibling-language domain (see
   index.html/en/index.html) — no JS, this isn't a client-side content
   swap. */
.lang-switch {
  pointer-events: auto;
  position: fixed;
  right: clamp(16px, 4vw, 36px);
  bottom: clamp(14px, 3vh, 26px);
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 10px 16px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: var(--shadow);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--text-dim);
}
.lang-switch .lang-current {
  color: var(--text);
}
.lang-switch .lang-sep {
  opacity: .4;
}
.lang-switch a {
  color: inherit;
  text-decoration: none;
  transition: color .2s ease;
}
.lang-switch a:hover,
.lang-switch a:focus-visible {
  color: var(--text);
}

/* ---------- Stage ---------- */
.stage {
  position: fixed;
  inset: 0;
  z-index: 3;
  pointer-events: none;
}

.focus-label {
  position: absolute;
  left: 50%;
  bottom: clamp(78px, 12vh, 110px);
  transform: translateX(-50%);
  font-size: 13px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-dim);
  padding: 8px 16px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--border);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  opacity: 0;
  /* Governs the *hide* transition (removing .visible lands back on this
     base rule, and a transition's timing comes from its target state) —
     deliberately longer than .visible's own .3s below. At an equal
     duration a 300ms fade genuinely reads as a pop the instant you're
     staring right at the label waiting for it to go away, even though the
     same 300ms felt fine on the way in (appearing unnoticed is far less
     jarring than vanishing while watched). !important so this specific,
     small opacity crossfade survives the reduced-motion media query below
     (which otherwise forces every transition site-wide to ~0ms) — unlike a
     parallax/spin/autoplay effect, a brief fade poses no vestibular risk,
     so it doesn't need to be killed along with everything else.
  */
  transition: opacity .6s ease, transform .6s ease, background-color .4s ease, border-color .4s ease, color .3s ease !important;
  white-space: nowrap;
  pointer-events: none;
  cursor: pointer;
  will-change: opacity;
}
.focus-label.visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
  pointer-events: auto;
  transition: opacity .3s ease, transform .3s ease, background-color .4s ease, border-color .4s ease, color .3s ease !important;
}
/* Set via showLabel(text, accentHex) in main.js — e.g. the "Skopiowano!"
   confirmation borrowing the copied tile's own accent color instead of the
   neutral tone plain tile-name labels use. */
.focus-label.accent { color: var(--label-accent); border-color: var(--label-accent); }

/* ---------- Hint bar ---------- */
.hint-bar {
  position: fixed;
  left: 50%;
  bottom: clamp(14px, 3vh, 26px);
  transform: translateX(-50%);
  z-index: 10;
  display: flex;
  gap: 18px;
  flex-wrap: wrap;
  justify-content: center;
  max-width: 92vw;
  font-size: 12px;
  color: var(--text-dim);
  pointer-events: none;
}
.hint { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }
.hint-or { opacity: .5; margin: 0 2px; }
kbd {
  font-family: inherit;
  font-size: 11px;
  border: 1px solid var(--border);
  background: var(--kbd-bg);
  border-radius: 5px;
  padding: 0 6px;
  margin: 0 1px;
  /* Plain inline text centers a letter (W/A/S/D) fine via symmetric padding,
     but the arrow glyphs (&uarr;/&larr;/&darr;/&rarr;) sit at odd
     baseline-relative positions depending on the font, reading visibly
     off-center inside the same box — inline-flex centers by actual glyph
     box instead of baseline, so both key sets line up the same way.
     A fixed height (rather than padding + line-height) is what keeps this
     the same visual weight as .key-cross kbd's fixed 22px square below —
     letting height float off padding/line-height instead left the
     standalone "Enter" key reading noticeably smaller/thinner next to the
     now-square WASD/arrow keys. Width stays padding-driven so "Enter"
     still gets to be wider than a single-letter key. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 22px;
  line-height: 1;
}

/* Keys laid out the way they sit on the keyboard (W above S, up-arrow above
   down-arrow) instead of a flat left-to-right row — reads at a glance
   instead of needing to be decoded. */
.key-cross {
  display: inline-grid;
  grid-template-columns: repeat(3, auto);
  grid-auto-rows: auto;
  gap: 2px;
  vertical-align: middle;
}
/* Square rather than kbd's usual pill shape — only scoped to the WASD/arrow
   cross, not the standalone "Enter" kbd elsewhere, which needs its own
   width to fit that word. Fixed width/height (not padding) is what makes it
   square regardless of glyph, since the inline-flex centering above already
   handles positioning the content within that fixed box. */
.key-cross kbd { margin: 0; width: 22px; height: 22px; padding: 0; }
.key-cross .k-up { grid-column: 2; grid-row: 1; }
.key-cross .k-left { grid-column: 1; grid-row: 2; }
.key-cross .k-down { grid-column: 2; grid-row: 2; }
.key-cross .k-right { grid-column: 3; grid-row: 2; }
.hint-touch { display: none; }
@media (hover: none) and (pointer: coarse) {
  .hint-mouse { display: none; }
  .hint-touch { display: inline-flex; }
  /* A touchscreen visitor has no keyboard in reach — drop the WASD/Enter
     hints entirely instead of just relabeling, so the bar stays one line. */
  .hint-key { display: none; }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.001ms !important; animation-duration: 0.001ms !important; }
}

/* ---------- Small screens ---------- */
@media (max-width: 600px) {
  .hint-bar {
    font-size: 11px;
    gap: 6px 10px;
    bottom: 10px;
    max-width: 96vw;
  }
  /* Screen's too narrow for the full hint row either way — keep only the
     single most relevant hint (mouse or touch, picked by the rule above). */
  .hint-key { display: none; }
  .focus-label { bottom: 64px; }
}
