/* =========================================================
   IMPERIUS.HU — Design system
   Fonts: Sora (display) + Inter (body), both Google Fonts — loaded via
   a <link> in each page's <head>, not @import here. @import forces the
   browser to fetch this stylesheet, parse it, discover the @import,
   and only then start the font request — one extra round trip added
   to every single page load for no reason.
   ========================================================= */

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html, body, h1, h2, h3, h4, p, figure, blockquote, dl, dd, ul, ol { margin: 0; }
ul[class], ol[class] { list-style: none; padding: 0; }
img, picture, svg { display: block; max-width: 100%; }
/* Same [hidden]-vs-author-display tie-break gotcha as elsewhere in this
   file: this reset's `display: block` on every svg beats the UA
   stylesheet's `[hidden] { display: none }`, so a hidden icon (like the
   now-playing widget's mute/unmute swap) would render anyway. */
svg[hidden] { display: none; }
input, button, textarea, select { font: inherit; color: inherit; }
a { color: inherit; text-decoration: none; }
button { cursor: pointer; background: none; border: none; }

/* ---------- Design tokens ---------- */
:root {
  --font-display: 'Sora', system-ui, sans-serif;
  --font-body: 'Inter', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, monospace;

  --radius-s: 10px;
  --radius-m: 16px;
  --radius-l: 24px;

  --container: 1180px;

  --accent: #8b6bff;
  --accent-2: #2fd9e8;
  --gradient: linear-gradient(135deg, var(--accent), var(--accent-2));

  --shadow-soft: 0 20px 60px -20px rgba(0,0,0,0.5);
  --ease: cubic-bezier(.16,.84,.44,1);
}

/* Dark theme (default) */
:root,
:root[data-theme="dark"] {
  --bg: #08080d;
  --bg-alt: #0f0f18;
  --surface: rgba(255,255,255,0.06);
  --surface-strong: rgba(255,255,255,0.1);
  --border: rgba(255,255,255,0.09);
  --text: #f3f3f8;
  --text-dim: #9d9db2;
  --text-faint: #6c6c82;
  --scrim: rgba(6,6,10,0.7);
  --bg-glow:
    radial-gradient(46vw 46vw at 18% 15%, color-mix(in srgb, #3b82f6 30%, transparent), transparent 68%),
    radial-gradient(52vw 52vw at 88% 8%, color-mix(in srgb, var(--accent) 24%, transparent), transparent 62%),
    radial-gradient(56vw 56vw at 6% 92%, color-mix(in srgb, var(--accent-2) 22%, transparent), transparent 62%),
    radial-gradient(44vw 44vw at 94% 90%, color-mix(in srgb, #60a5fa 26%, transparent), transparent 68%);
}

/* Light theme */
:root[data-theme="light"] {
  --bg: #f6f5fb;
  --bg-alt: #ffffff;
  --surface: rgba(20,15,40,0.05);
  --surface-strong: rgba(20,15,40,0.08);
  --border: rgba(20,15,40,0.09);
  --text: #16151f;
  --text-dim: #55536b;
  --text-faint: #85839a;
  --scrim: rgba(255,255,255,0.7);
  --accent: #6d3df0;
  --accent-2: #0aa9bb;
  --bg-glow:
    radial-gradient(46vw 46vw at 18% 15%, color-mix(in srgb, #3b82f6 19%, transparent), transparent 68%),
    radial-gradient(52vw 52vw at 88% 8%, color-mix(in srgb, #6d3df0 15%, transparent), transparent 62%),
    radial-gradient(56vw 56vw at 6% 92%, color-mix(in srgb, #0aa9bb 14%, transparent), transparent 62%),
    radial-gradient(44vw 44vw at 94% 90%, color-mix(in srgb, #60a5fa 17%, transparent), transparent 68%);
  --shadow-soft: 0 20px 60px -24px rgba(30,20,60,0.25);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- Base ---------- */
html { scroll-behavior: smooth; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  transition: background .4s var(--ease), color .4s var(--ease);
}

/* Ambient animated background — four soft, bluish glows that drift
   slowly. `inset: -10%` gives it overscan room so the drift/scale never
   reveals a hard edge; only `transform` is animated (GPU-cheap, no
   repaint), same discipline as the preloader — see the Teljesítmény
   section in README.md for why that matters here. */
body::before {
  content: '';
  position: fixed;
  inset: -10%;
  z-index: -2;
  background: var(--bg-glow);
  animation: bg-drift 30s ease-in-out infinite alternate;
  pointer-events: none;
}
@keyframes bg-drift {
  0% { transform: translate(0, 0) scale(1); }
  50% { transform: translate(-2.5%, 2%) scale(1.05); }
  100% { transform: translate(2.5%, -2%) scale(1); }
}

/* Second ambient layer: columns of code quietly scrolling upward,
   behind everything, on every page (injected once by main.js so it
   isn't duplicated by hand across every HTML file). Each column's
   text is rendered ONCE and only ever animated via `transform`, same
   as the glow above — no per-frame JS, no layout work, so it costs
   nothing to keep running for as long as the tab stays open. */
.code-bg {
  position: fixed;
  inset: 0;
  z-index: -1;
  display: flex;
  justify-content: space-between;
  gap: 2vw;
  padding-inline: 3vw;
  overflow: hidden;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, transparent, black 18%, black 82%, transparent);
  mask-image: linear-gradient(to bottom, transparent, black 18%, black 82%, transparent);
}
.code-col {
  font-family: var(--font-mono);
  font-size: .8rem;
  line-height: 2;
  white-space: pre;
  color: color-mix(in srgb, var(--accent-2) 70%, transparent);
  opacity: .16;
  animation: code-scroll linear infinite;
  will-change: transform;
}
.code-col:nth-child(3n+1) { color: color-mix(in srgb, var(--accent) 70%, transparent); }
.code-col:nth-child(3n+2) { color: color-mix(in srgb, #3b82f6 75%, transparent); }
:root[data-theme="light"] .code-col { opacity: .12; }
@keyframes code-scroll {
  from { transform: translateY(0); }
  to { transform: translateY(-50%); }
}
@media (max-width: 900px) { .code-bg { display: none; } }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
}

h1 { font-size: clamp(2.4rem, 5.5vw, 4.2rem); }
h2 { font-size: clamp(1.8rem, 3.4vw, 2.6rem); }
h3 { font-size: clamp(1.2rem, 2vw, 1.5rem); }

p { color: var(--text-dim); }

::selection { background: var(--accent); color: #fff; }

/* Custom scrollbar: an inset gradient pill, not the browser default */
* { scrollbar-width: thin; scrollbar-color: var(--accent) transparent; }
::-webkit-scrollbar { width: 16px; height: 16px; }
::-webkit-scrollbar-track { background: var(--bg); }
::-webkit-scrollbar-thumb {
  background-color: var(--accent);
  background-image: var(--gradient);
  border-radius: 999px;
  border: 5px solid var(--bg);
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { border-width: 4px; }
::-webkit-scrollbar-corner { background: var(--bg); }

/* Scroll progress bar — fills as the page is read */
#scroll-progress-track {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 3px;
  z-index: 600;
  pointer-events: none;
  background: transparent;
}
#scroll-progress-track span {
  display: block;
  height: 100%;
  width: 0%;
  background: var(--gradient);
  box-shadow: 0 0 14px color-mix(in srgb, var(--accent) 65%, transparent);
}

/* Custom cursor — a small "+" reticle, desktop fine-pointer only (see
   main.js). Same size and color in every state; hovering an
   interactive element only rotates it 45° into an "×", nothing else. */
html.has-custom-cursor, html.has-custom-cursor * { cursor: none !important; }
/* The universal `*` above doesn't reach into a range input's thumb —
   ::-webkit-slider-thumb/::-moz-range-thumb are UA shadow parts, not
   matched by a bare `*` selector — so any slider's own `cursor: pointer`
   (e.g. the now-playing volume slider) kept showing the native pointer
   right where visitors actually drag it. */
html.has-custom-cursor input[type="range"]::-webkit-slider-thumb,
html.has-custom-cursor input[type="range"]::-moz-range-thumb { cursor: none !important; }
.cursor-ring {
  /* Positioned via translate3d in JS (main.js) — that inline transform
     replaces any transform set here entirely, so the rotation lives on
     the .cursor-ring-mark child instead, which JS never touches. */
  position: fixed; top: 0; left: 0; pointer-events: none; z-index: 9998; opacity: 0;
  width: 18px; height: 18px; margin: -9px 0 0 -9px;
  transition: opacity .2s;
}
.cursor-ring-mark {
  position: absolute; inset: 0;
  transition: transform .3s var(--ease);
}
.cursor-ring-mark::before, .cursor-ring-mark::after {
  content: '';
  position: absolute;
  background: var(--accent);
}
.cursor-ring-mark::before { top: 50%; left: 0; right: 0; height: 2px; transform: translateY(-50%); }
.cursor-ring-mark::after { left: 50%; top: 0; bottom: 0; width: 2px; transform: translateX(-50%); }
.cursor-ring.is-hover .cursor-ring-mark { transform: rotate(45deg); }
@media (max-width: 860px) { .cursor-ring { display: none; } }

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 4vw, 2.5rem);
}

.section { padding-block: clamp(4rem, 9vw, 7rem); }
.section-head { max-width: 640px; margin-bottom: clamp(2rem, 5vw, 3.5rem); }
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  font-family: var(--font-display);
  font-size: .78rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: .9rem;
}
.eyebrow::before {
  content: '';
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--gradient);
}

.gradient-text {
  background: var(--gradient);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.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;
}

.skip-link {
  position: fixed;
  top: -60px; left: 1rem;
  background: var(--accent);
  color: #fff;
  padding: .7rem 1.2rem;
  border-radius: var(--radius-s);
  z-index: 999;
  transition: top .25s var(--ease);
}
.skip-link:focus { top: 1rem; }

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

/* Scroll reveal */
[data-reveal] {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
}
[data-reveal].in-view { opacity: 1; transform: translateY(0); }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  padding: .85rem 1.5rem;
  border-radius: 999px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: .95rem;
  white-space: nowrap;
  transition: transform .3s var(--ease), box-shadow .3s var(--ease), background .3s var(--ease), border-color .3s var(--ease);
}
.btn:hover { transform: translateY(-2px); }
.btn-primary {
  background: var(--gradient);
  color: #08080d;
  box-shadow: 0 10px 30px -10px color-mix(in srgb, var(--accent) 60%, transparent);
}
.btn-primary:hover { box-shadow: 0 16px 40px -12px color-mix(in srgb, var(--accent) 70%, transparent); }
.btn-ghost {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
}
.btn-ghost:hover { border-color: var(--accent); background: var(--surface-strong); }
.btn-sm { padding: .6rem 1.1rem; font-size: .85rem; }

/* ---------- Preloader ---------- */
#preloader {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  overflow: hidden;
  transition: opacity .4s var(--ease), visibility .4s var(--ease);
}
#preloader.is-hidden { opacity: 0; visibility: hidden; pointer-events: none; }

/* A single soft, STATIC ambient glow — no filter:blur, no animation.
   A radial-gradient already fades softly on its own, so it gives the
   same "ambient light" mood as the old animated, blurred blobs used
   to, at effectively zero runtime cost. */
.loader-bg {
  position: absolute; inset: 0; overflow: hidden;
  background:
    radial-gradient(45% 45% at 25% 20%, color-mix(in srgb, var(--accent) 16%, transparent), transparent 70%),
    radial-gradient(45% 45% at 78% 82%, color-mix(in srgb, var(--accent-2) 14%, transparent), transparent 70%);
}

.loader-content { position: relative; display: flex; flex-direction: column; align-items: center; gap: 1.3rem; }

/* ---------- The centerpiece: a liquid, rotating gradient orb ----------
   Every animation here only ever touches `transform`, `border-radius`
   and `opacity` — never `filter` or `background-position` — so the
   compositor can run all of it without repainting anything, no matter
   how long the loader is on screen. */
.loader-orb-wrap { position: relative; width: 104px; height: 104px; display: grid; place-items: center; }

.loader-orb {
  position: absolute; inset: 8px;
  background: conic-gradient(from 0deg, var(--accent), var(--accent-2), var(--accent));
  animation: orb-spin 3.2s linear infinite, orb-morph 5s ease-in-out infinite;
  box-shadow: 0 0 30px color-mix(in srgb, var(--accent) 45%, transparent);
}
@keyframes orb-spin { to { transform: rotate(360deg); } }
@keyframes orb-morph {
  0%, 100% { border-radius: 42% 58% 65% 35% / 45% 45% 55% 55%; }
  33%      { border-radius: 62% 38% 30% 70% / 60% 32% 68% 40%; }
  66%      { border-radius: 35% 65% 55% 45% / 38% 62% 38% 62%; }
}

/* Three small satellites orbiting the core in the opposite direction. */
.loader-orbit { position: absolute; inset: 0; animation: orb-spin 5s linear infinite reverse; }
.loader-orbit span {
  position: absolute; top: 50%; left: 50%;
  width: 6px; height: 6px; margin: -3px 0 0 -3px;
  border-radius: 50%;
  background: var(--accent-2);
  box-shadow: 0 0 8px color-mix(in srgb, var(--accent-2) 80%, transparent);
}
.loader-orbit span:nth-child(1) { transform: rotate(0deg) translateY(-56px); }
.loader-orbit span:nth-child(2) { transform: rotate(120deg) translateY(-56px); }
.loader-orbit span:nth-child(3) { transform: rotate(240deg) translateY(-56px); }

/* The brand mark sits still at the center, on top of the spinning orb. */
.loader-mark {
  position: relative;
  width: 34px; height: 34px;
  border-radius: 10px;
  background: var(--bg);
  display: grid; place-items: center;
  animation: mark-pulse 1.8s ease-in-out infinite;
}
/* A plain centered bar, not the brand mark's asymmetric flag-notch
   shape — that shape's own clip-path only renders its left ~45%, so
   the *visible* bar sat left-of-center inside its (correctly centered)
   box. A symmetric shape is centered by construction, no math needed. */
.loader-mark::after {
  content: '';
  width: 5px; height: 19px;
  border-radius: 1px;
  background: var(--text);
}
@keyframes mark-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.1); } }

/* A slim progress bar — the fill width-transition and a translateX
   sheen sweep are the only moving parts, both cheap. */
.loader-bar-track {
  position: relative;
  width: 200px; height: 8px;
  border-radius: 999px;
  background: var(--surface-strong);
  border: 1px solid var(--border);
  overflow: hidden;
}
.loader-bar-fill {
  position: relative;
  height: 100%; width: 0%;
  background: var(--gradient);
  border-radius: 999px;
  transition: width .15s linear;
  box-shadow: 0 0 14px color-mix(in srgb, var(--accent) 60%, transparent);
}
.loader-bar-sheen {
  position: absolute; top: 0; bottom: 0; left: 0;
  width: 45%;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.5), transparent);
  transform: translateX(-220%);
  animation: sheen-sweep 1.4s linear infinite;
  mix-blend-mode: overlay;
}
@keyframes sheen-sweep { to { transform: translateX(320%); } }

.loader-percent {
  font-family: var(--font-mono);
  font-size: 1.7rem;
  font-weight: 700;
  background: var(--gradient);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-variant-numeric: tabular-nums;
}
.loader-status {
  font-family: var(--font-mono);
  font-size: .82rem;
  color: var(--text-faint);
  min-height: 1.3em;
  letter-spacing: .01em;
}

/* ---------- Typewriter section reveal ---------- */
[data-typewriter] { display: flex; align-items: baseline; gap: .55rem; flex-wrap: wrap; }
.tw-prompt { font-family: var(--font-mono); color: var(--accent); font-weight: 600; }
.tw-target { font-family: var(--font-mono); }
.tw-target.typing::after {
  content: '▍';
  display: inline-block;
  margin-left: 2px;
  color: var(--accent-2);
  animation: tw-blink .9s step-end infinite;
}
@keyframes tw-blink { 50% { opacity: 0; } }

/* Page fade-in (progressive enhancement) */
/* Note: intentionally opacity-only — a transform here (even an identity
   one left behind by animation-fill-mode) would turn body into the
   containing block for its position:fixed children (header, preloader,
   mobile menu), breaking them site-wide. */
body.page-transition-ready { animation: page-in .5s var(--ease) both; }
@keyframes page-in { from { opacity: 0; } to { opacity: 1; } }
body.page-transition-out { opacity: 0; transition: opacity .28s var(--ease); }

/* ---------- Navbar ---------- */
.site-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 500;
  padding-block: .9rem;
}
.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .55rem .6rem .55rem 1.1rem;
  border-radius: 999px;
  /* A lighter blur than a typical frosted-glass nav — this bar stays
     fixed on screen through every scroll frame, so a heavy compound
     filter (blur+saturate) here is a real, continuous cost, not a
     one-time one. Raising the backing opacity compensates visually. */
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  border: 1px solid var(--border);
  backdrop-filter: blur(8px);
  box-shadow: var(--shadow-soft);
}
.brand {
  display: flex;
  align-items: center;
  gap: .6rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: -0.01em;
}
.brand-mark {
  width: 30px; height: 30px;
  border-radius: 9px;
  background: var(--gradient);
  position: relative;
  flex-shrink: 0;
}
.brand-mark::after {
  content: '';
  position: absolute; inset: 6px;
  border-radius: 4px;
  background: var(--bg);
  clip-path: polygon(0 0, 45% 0, 45% 100%, 0 100%);
}

.nav-links {
  display: flex;
  align-items: center;
  gap: .2rem;
}
.nav-links a {
  position: relative;
  padding: .55rem .9rem;
  font-size: .92rem;
  font-weight: 500;
  color: var(--text-dim);
  border-radius: 999px;
  transition: color .25s var(--ease), background .25s var(--ease);
}
.nav-links a:hover { color: var(--text); background: var(--surface); }
.nav-links a.active { color: var(--text); }
.nav-links a.active::after {
  content: '';
  position: absolute;
  left: 1rem; right: 1rem; bottom: .3rem;
  height: 2px;
  border-radius: 2px;
  background: var(--gradient);
}

.nav-actions { display: flex; align-items: center; gap: .5rem; }

.theme-toggle {
  width: 40px; height: 40px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: var(--surface);
  border: 1px solid var(--border);
  transition: background .25s var(--ease), transform .25s var(--ease);
}
.theme-toggle:hover { background: var(--surface-strong); transform: rotate(-12deg); }
.theme-toggle svg { width: 18px; height: 18px; }
.theme-toggle .icon-sun { display: none; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: none; }
:root[data-theme="light"] .theme-toggle .icon-sun { display: block; }

.lang-toggle, .search-toggle {
  height: 40px;
  min-width: 40px;
  padding-inline: .7rem;
  border-radius: 999px;
  display: grid; place-items: center;
  background: var(--surface);
  border: 1px solid var(--border);
  transition: background .25s var(--ease);
}
.lang-toggle { font-family: var(--font-display); font-weight: 700; font-size: .78rem; letter-spacing: .02em; }
.lang-toggle:hover, .search-toggle:hover { background: var(--surface-strong); }
.search-toggle svg { width: 17px; height: 17px; }

.nav-toggle {
  display: none;
  width: 40px; height: 40px;
  border-radius: 50%;
  background: var(--surface);
  border: 1px solid var(--border);
  place-items: center;
  flex-direction: column;
  gap: 4px;
}
.nav-toggle span {
  width: 16px; height: 2px;
  background: var(--text);
  border-radius: 2px;
  transition: transform .3s var(--ease), opacity .3s var(--ease);
}

.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 400;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: .5rem;
  padding: 2rem clamp(1.5rem, 8vw, 4rem);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: opacity .35s var(--ease), transform .35s var(--ease), visibility .35s;
}
.mobile-menu.is-open { opacity: 1; visibility: visible; transform: translateY(0); }
.mobile-menu a {
  font-family: var(--font-display);
  font-size: clamp(1.8rem, 8vw, 2.6rem);
  font-weight: 700;
  color: var(--text-dim);
  padding: .4rem 0;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .4s var(--ease), transform .4s var(--ease), color .25s;
}
.mobile-menu.is-open a { opacity: 1; transform: translateY(0); }
.mobile-menu a:hover, .mobile-menu a.active { color: var(--text); }
.mobile-menu a.active { background: var(--gradient); -webkit-background-clip: text; background-clip: text; color: transparent; }

@media (max-width: 860px) {
  .nav-links { display: none; }
  .nav-toggle { display: grid; }
}

body.nav-open { overflow: hidden; }

/* ---------- Hero ---------- */
.hero {
  padding-top: clamp(8rem, 16vw, 11rem);
  padding-bottom: clamp(3rem, 6vw, 5rem);
  position: relative;
}
.hero-grid {
  display: grid;
  grid-template-columns: 1.1fr .9fr;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}
/* Grid items default to min-width: auto, i.e. never narrower than their
   widest unshrinkable child (here, the now-playing volume slider) — so
   without this the whole column (and the text inside it) refused to
   shrink below that width and overflowed narrow viewports instead of
   wrapping/resizing normally. */
.hero-grid > * { min-width: 0; }
@media (max-width: 900px) { .hero-grid { grid-template-columns: 1fr; } }

.hero-tagline { font-size: clamp(1.05rem, 1.6vw, 1.2rem); max-width: 46ch; margin-block: 1.4rem 2rem; }
.hero-actions { display: flex; flex-wrap: wrap; gap: .8rem; }

.hero-stats {
  display: flex;
  gap: clamp(1.2rem, 3vw, 2.4rem);
  margin-top: 2.8rem;
  flex-wrap: wrap;
}
.hero-stat b { display: block; font-family: var(--font-display); font-size: 1.5rem; }
.hero-stat span { font-size: .85rem; color: var(--text-faint); }

.hero-visual {
  position: relative;
  width: 100%;
  aspect-ratio: 1;
  max-width: 420px;
  margin-inline: auto;
  animation: float 7s ease-in-out infinite;
}
.hero-glow {
  position: absolute; inset: 12%;
  border-radius: 50%;
  background: var(--gradient);
  filter: blur(28px);
  opacity: .55;
}
.hero-avatar {
  position: absolute; inset: 14%;
  border-radius: 50%;
  overflow: hidden;
  padding: 4px;
  background: var(--gradient);
  box-shadow: var(--shadow-soft);
}
.hero-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; display: block; border: 3px solid var(--bg); }
/* Decorative ring — SVG stroke-dasharray renders crisp & anti-aliased at
   any rotation, unlike a CSS `border-style: dashed` circle (which looked
   chunky/choppy when spun). Concentric with .hero-avatar via matching inset. */
.hero-ring-wrap {
  position: absolute; inset: -4%;
  animation: spin-slow 40s linear infinite;
}
/* The <svg> is sized via a plain wrapper div rather than percentage
   width/height on the svg itself — SVG root elements resolve CSS
   percentage sizing inconsistently with `inset` on some engines, which
   was rendering this ring as a non-square, off-center box. */
.hero-ring-wrap svg { display: block; width: 100%; height: 100%; }
.hero-ring-wrap circle { fill: none; stroke: var(--accent); opacity: .55; stroke-width: 1; stroke-dasharray: 2 7; stroke-linecap: round; }
@keyframes float { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-14px); } }
@keyframes spin-slow { to { transform: rotate(360deg); } }

/* ---------- Now playing widget ---------- */
.now-playing {
  display: flex; flex-direction: column; gap: .8rem;
  padding: 1rem 1.1rem;
  margin-top: 2.2rem;
  max-width: 340px;
}
/* Same tie-breaking gotcha as .quiz-new-best above: an author rule's
   `display` beats the UA stylesheet's `[hidden] { display: none }` at
   equal specificity, regardless of source order. */
.now-playing[hidden] { display: none; }
.now-playing-top { display: flex; align-items: center; gap: 1rem; }
.now-playing-art {
  position: relative;
  width: 50px; height: 50px;
  border-radius: 10px;
  overflow: hidden;
  flex-shrink: 0;
  background: var(--bg-alt);
  transition: box-shadow .25s var(--ease);
}
.now-playing-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.now-playing.is-playing .now-playing-art { box-shadow: 0 0 0 2px var(--accent); }
.now-playing-info { min-width: 0; }
.now-playing-label {
  display: block;
  font-size: .7rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-faint); margin-bottom: .2rem;
}
.now-playing-info b {
  display: block; font-size: .9rem; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.now-playing-progress { display: flex; align-items: center; gap: .6rem; }
.now-playing-progress-track {
  flex: 1; height: 4px;
  border-radius: 999px;
  background: var(--surface-strong);
  overflow: hidden;
}
.now-playing-progress-fill {
  height: 100%; width: 0%;
  background: var(--gradient);
  border-radius: 999px;
  transition: width .3s linear;
}
.now-playing-time {
  font-family: var(--font-mono);
  font-size: .72rem;
  color: var(--text-faint);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* Three distinct, separately-clickable controls — not one button that
   swaps its own icon/meaning depending on state. */
.now-playing-controls { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.now-playing-btn {
  flex-shrink: 0;
  width: 32px; height: 32px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  transition: background .2s var(--ease), border-color .2s var(--ease), color .2s var(--ease), transform .15s var(--ease);
}
.now-playing-btn:hover { border-color: var(--accent); transform: translateY(-1px); }
.now-playing-btn svg { width: 14px; height: 14px; }
.now-playing-btn.is-active { background: var(--gradient); color: #08080d; border-color: transparent; }

.now-playing-volume { display: flex; align-items: center; gap: .5rem; margin-left: auto; flex: 1; min-width: 90px; }
.now-playing-mute {
  flex-shrink: 0;
  width: 28px; height: 28px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: none;
  border: none;
  color: var(--text-faint);
  transition: color .2s var(--ease);
}
.now-playing-mute:hover { color: var(--accent); }
.now-playing-mute svg { width: 16px; height: 16px; }

/* A custom-styled range input — the filled portion (left of the thumb)
   is painted via a JS-updated background-image gradient, see
   now-playing.js, rather than relying on browser-specific
   ::-webkit-slider-runnable-track / ::-moz-range-progress rules that
   don't render consistently the same way across engines. */
.now-playing-volume-slider {
  flex: 1;
  min-width: 0;
  -webkit-appearance: none;
  appearance: none;
  height: 4px;
  border-radius: 999px;
  background: var(--surface-strong);
  outline: none;
  cursor: pointer;
}
.now-playing-volume-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
  border: 2px solid var(--bg-alt);
  box-shadow: 0 0 0 1px var(--accent);
}
.now-playing-volume-slider::-moz-range-thumb {
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
  border: 2px solid var(--bg-alt);
  box-shadow: 0 0 0 1px var(--accent);
}
.now-playing-volume-slider::-moz-range-track { background: transparent; }

/* The real YouTube iframe lives here, clipped to invisible — the
   widget above is a custom-styled remote for it. */
.now-playing-error {
  font-size: .78rem;
  color: #ff8a8a;
  line-height: 1.5;
  margin: 0;
}
.now-playing-error a { color: var(--accent-2); text-decoration: underline; }
.now-playing-error[hidden] { display: none; }
.now-playing-frame-wrap { position: absolute; width: 2px; height: 2px; overflow: hidden; opacity: 0; pointer-events: none; }

/* ---------- Cards ---------- */
/* No backdrop-filter here on purpose: with a few dozen cards on a grid
   page (videos, portfolio) a blurred glass panel per card is a classic
   scroll-FPS killer — the browser re-samples and blurs whatever's
   behind every single one of them on every frame. A flat translucent
   background reads as "glass" almost as well, for near-zero cost. */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-m);
  transition: transform .35s var(--ease), border-color .35s var(--ease), background .35s var(--ease);
}
.card:hover { transform: translateY(-4px); border-color: color-mix(in srgb, var(--accent) 50%, var(--border)); background: var(--surface-strong); }

.grid {
  display: grid;
  gap: 1.4rem;
}
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 900px) { .grid-3, .grid-2 { grid-template-columns: 1fr 1fr; } }
@media (max-width: 620px) { .grid-3, .grid-2 { grid-template-columns: 1fr; } }
@media (max-width: 1000px) { .grid-4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .grid-4 { grid-template-columns: 1fr; } }

/* Video card */
.video-card { overflow: hidden; }
.video-thumb {
  position: relative;
  aspect-ratio: 16/9;
  overflow: hidden;
  background: var(--bg-alt);
}
.video-thumb img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s var(--ease); }
.video-card:hover .video-thumb img { transform: scale(1.06); }
.video-badge {
  position: absolute; top: .6rem; right: .6rem;
  background: var(--scrim);
  color: var(--text);
  font-size: .7rem;
  font-family: var(--font-display);
  letter-spacing: .04em;
  padding: .25rem .55rem;
  border-radius: 999px;
  border: 1px solid var(--border);
}
.play-glyph {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  opacity: 0;
  transition: opacity .3s var(--ease);
  background: linear-gradient(0deg, rgba(0,0,0,.35), transparent 60%);
}
.video-card:hover .play-glyph { opacity: 1; }
.play-glyph svg {
  width: 46px; height: 46px;
  filter: drop-shadow(0 6px 16px rgba(0,0,0,.4));
}
.video-body { padding: 1.1rem 1.2rem 1.3rem; }
.video-body h4 { font-size: 1rem; font-weight: 600; margin-bottom: .4rem; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.video-meta { font-size: .82rem; color: var(--text-faint); }

.video-skeleton {
  aspect-ratio: 16/9;
  border-radius: var(--radius-m);
  background: linear-gradient(100deg, var(--surface) 30%, var(--surface-strong) 50%, var(--surface) 70%);
  background-size: 200% 100%;
  animation: shimmer 1.4s infinite;
}
@keyframes shimmer { to { background-position: -200% 0; } }

.filter-row { display: flex; gap: .6rem; margin-bottom: 2rem; flex-wrap: wrap; }
.filter-btn {
  padding: .5rem 1.1rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  font-size: .85rem;
  font-weight: 500;
  color: var(--text-dim);
  transition: all .25s var(--ease);
}
.filter-btn.active, .filter-btn:hover { color: var(--text); border-color: var(--accent); background: var(--surface-strong); }

/* Generic content card */
/* Shared badge look — a small gradient square housing an icon.
   Contexts below only need to override size/spacing as needed. */
.icon-badge {
  width: 44px; height: 44px;
  border-radius: 12px;
  background: var(--gradient);
  display: grid; place-items: center;
  flex-shrink: 0;
}
.icon-badge svg { width: 22px; height: 22px; color: #08080d; }

.info-card { padding: 1.6rem; }
.info-card .icon-badge { margin-bottom: 1rem; }
.info-card h3 { margin-bottom: .5rem; }
.info-card p { font-size: .93rem; }

/* Partner strip */
.partner-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}
.partner-chip {
  display: flex; align-items: center; gap: .6rem;
  padding: .8rem 1.3rem;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--border);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: .95rem;
  transition: border-color .25s var(--ease), transform .25s var(--ease);
}
.partner-chip:hover { border-color: var(--accent); transform: translateY(-2px); }
.partner-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--gradient); }

/* CTA banner */
.cta-banner {
  border-radius: var(--radius-l);
  padding: clamp(2.4rem, 6vw, 4rem);
  background: var(--surface);
  border: 1px solid var(--border);
  position: relative;
  overflow: hidden;
  text-align: center;
}
.cta-banner::before {
  content: '';
  position: absolute; inset: -40%;
  background: radial-gradient(circle at center, color-mix(in srgb, var(--accent) 18%, transparent), transparent 65%);
  pointer-events: none;
}
.cta-banner h2 { margin-bottom: .8rem; }
.cta-banner p { max-width: 50ch; margin-inline: auto 1.6rem; }
.cta-banner .hero-actions { justify-content: center; margin-top: 1.6rem; }

/* ---------- About page ---------- */
.about-grid {
  display: grid;
  grid-template-columns: .8fr 1.2fr;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}
@media (max-width: 860px) { .about-grid { grid-template-columns: 1fr; } }
.about-photo {
  border-radius: var(--radius-l);
  overflow: hidden;
  border: 1px solid var(--border);
  position: sticky;
  top: 7rem;
}
.about-photo img { width: 100%; aspect-ratio: 1; object-fit: cover; }
.tag-row { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1.4rem; }
.tag { padding: .4rem .9rem; border-radius: 999px; background: var(--surface); border: 1px solid var(--border); font-size: .8rem; color: var(--text-dim); }

.timeline { border-left: 1px solid var(--border); padding-left: 1.6rem; display: grid; gap: 1.8rem; margin-top: 1rem; }
.timeline-item { position: relative; }
.timeline-item::before {
  content: '';
  position: absolute; left: -1.68rem; top: .3rem;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--gradient);
}
.timeline-item time { font-family: var(--font-display); font-size: .8rem; color: var(--accent); letter-spacing: .04em; }
.timeline-item h4 { margin-block: .3rem .3rem; }

/* ---------- Portfolio ---------- */
.project-card { padding: 1.1rem; display: flex; flex-direction: column; gap: .5rem; height: 100%; }
.project-card .icon-badge { width: 32px; height: 32px; border-radius: 9px; }
.project-card .icon-badge svg { width: 16px; height: 16px; }
.project-card h3 { font-size: 1.02rem; }
.project-card p { font-size: .87rem; }
.project-tags { display: flex; gap: .35rem; flex-wrap: wrap; }
.project-tags span { font-size: .68rem; padding: .18rem .55rem; border-radius: 999px; background: var(--surface-strong); color: var(--text-faint); }
.project-link { margin-top: auto; font-size: .84rem; font-weight: 600; color: var(--accent); display: inline-flex; align-items: center; gap: .35rem; }

/* ---------- Contact ---------- */
.contact-grid { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(2rem, 5vw, 3.5rem); }
@media (max-width: 860px) { .contact-grid { grid-template-columns: 1fr; } }
.contact-list { display: grid; gap: .9rem; margin-top: 1.6rem; }
.contact-list a, .contact-list div {
  display: flex; align-items: center; gap: .9rem;
  padding: 1rem 1.2rem;
  border-radius: var(--radius-m);
  background: var(--surface);
  border: 1px solid var(--border);
  transition: border-color .25s var(--ease), transform .25s var(--ease);
}
.contact-list a:hover { border-color: var(--accent); transform: translateX(4px); }
.contact-list .icon-badge { width: 38px; height: 38px; border-radius: 10px; background: var(--gradient); display: grid; place-items: center; flex-shrink: 0; }
.contact-list .icon-badge svg { width: 18px; height: 18px; color: #08080d; }
.contact-list b { display: block; font-size: .95rem; }
.contact-list span { font-size: .82rem; color: var(--text-faint); }

.field { display: grid; gap: .5rem; margin-bottom: 1.2rem; }
.field label { font-size: .85rem; font-weight: 600; }
.field input, .field textarea {
  padding: .85rem 1rem;
  border-radius: var(--radius-s);
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  transition: border-color .25s var(--ease), background .25s var(--ease);
}
.field input:focus, .field textarea:focus { border-color: var(--accent); background: var(--surface-strong); }
.field textarea { resize: vertical; min-height: 130px; }
.form-note { font-size: .8rem; color: var(--text-faint); margin-top: .8rem; }

/* ---------- Footer ---------- */
.site-footer { border-top: 1px solid var(--border); padding-block: 3rem 2rem; margin-top: 4rem; }
.footer-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: 2.5rem;
}
@media (max-width: 700px) { .footer-grid { grid-template-columns: 1fr; } }
.footer-grid h4 { font-size: .85rem; text-transform: uppercase; letter-spacing: .08em; color: var(--text-faint); margin-bottom: 1rem; }
.footer-links { display: grid; gap: .6rem; }
.footer-links a { color: var(--text-dim); font-size: .92rem; transition: color .2s; }
.footer-links a:hover { color: var(--accent); }
.footer-bottom {
  display: flex; justify-content: space-between; align-items: center;
  margin-top: 2.5rem; padding-top: 1.5rem;
  border-top: 1px solid var(--border);
  font-size: .82rem; color: var(--text-faint);
  flex-wrap: wrap; gap: 1rem;
}
.footer-social { display: flex; gap: .6rem; }
.footer-social a {
  width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--surface); border: 1px solid var(--border);
  transition: all .25s var(--ease);
}
.footer-social a:hover { border-color: var(--accent); color: var(--accent); transform: translateY(-3px); }
.footer-social svg { width: 17px; height: 17px; }

/* ---------- Search ---------- */
.search-overlay {
  position: fixed; inset: 0;
  z-index: 700;
  background: var(--scrim);
  backdrop-filter: blur(8px);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 10vh 1.25rem 2rem;
}
.search-overlay[hidden] { display: none; }
.search-panel {
  width: 100%; max-width: 560px;
  background: var(--bg-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius-l);
  box-shadow: var(--shadow-soft);
  overflow: hidden;
  animation: search-in .25s var(--ease);
}
@keyframes search-in { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } }
.search-input-row { display: flex; align-items: center; gap: .7rem; padding: 1rem 1.2rem; border-bottom: 1px solid var(--border); }
.search-input-row svg { width: 20px; height: 20px; color: var(--text-faint); flex-shrink: 0; }
.search-input-row input { flex: 1; background: none; border: none; color: var(--text); font-size: 1rem; }
.search-input-row input:focus { outline: none; }
.search-input-row button { color: var(--text-faint); width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; }
.search-input-row button:hover { background: var(--surface); color: var(--text); }
.search-results { max-height: 50vh; overflow-y: auto; padding: .6rem; }
.search-group-label { font-size: .72rem; text-transform: uppercase; letter-spacing: .08em; color: var(--text-faint); padding: .7rem .8rem .3rem; }
.search-result { display: flex; flex-direction: column; gap: .15rem; padding: .7rem .8rem; border-radius: var(--radius-s); transition: background .2s; }
.search-result:hover { background: var(--surface); }
.search-result b { font-size: .92rem; font-weight: 600; }
.search-result span { font-size: .78rem; color: var(--text-faint); }
.search-hint { padding: .7rem 1.2rem; font-size: .75rem; color: var(--text-faint); border-top: 1px solid var(--border); margin: 0; }

/* ---------- Stats ---------- */
.stats-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.4rem; }
.stat-card { padding: 2rem 1.5rem; text-align: center; }
.stat-card b {
  display: block;
  font-family: var(--font-mono);
  font-size: clamp(1.8rem, 4vw, 2.4rem);
  background: var(--gradient);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-variant-numeric: tabular-nums;
}
.stat-card span { color: var(--text-faint); font-size: .85rem; }
@media (max-width: 700px) { .stats-grid { grid-template-columns: 1fr; } }

/* ---------- YouTube Live embed ---------- */
.embed-frame-wrap {
  border-radius: var(--radius-l);
  overflow: hidden;
  border: 1px solid var(--border);
  aspect-ratio: 16/9;
  background: var(--bg-alt);
}
.embed-frame { width: 100%; height: 100%; border: 0; }
.live-offline {
  width: 100%; height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .6rem;
  text-align: center;
  padding: 2rem;
}
.live-offline .icon-badge { margin-bottom: .2rem; }
.live-offline p { max-width: 36ch; }

/* ---------- Knowledge tree quiz ---------- */
.quiz-layout {
  display: grid;
  grid-template-columns: 80px 1fr;
  gap: clamp(1.5rem, 4vw, 3rem);
  align-items: start;
}
@media (max-width: 700px) { .quiz-layout { grid-template-columns: 1fr; } }

.quiz-climb {
  position: relative;
  justify-self: center;
  width: 18px;
  height: clamp(220px, 36vw, 320px);
  border-radius: 999px;
  background: var(--surface-strong);
  border: 1px solid var(--border);
  overflow: visible;
}
.quiz-climb-fill {
  position: absolute; bottom: 0; left: 0; right: 0;
  height: 0%;
  background: var(--gradient);
  border-radius: 999px;
  transition: height .5s var(--ease);
}
.quiz-climb-marker {
  position: absolute; top: -11px; left: 50%;
  width: 22px; height: 22px; margin-left: -11px;
  border-radius: 50%;
  background: var(--gradient);
  box-shadow: 0 0 14px color-mix(in srgb, var(--accent) 55%, transparent);
}

.quiz-panel { max-width: 560px; }
.quiz-stats { display: flex; gap: 1.8rem; margin-bottom: 1.6rem; }
.quiz-stat b {
  display: block;
  font-family: var(--font-mono);
  font-size: 1.7rem;
  background: var(--gradient);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-variant-numeric: tabular-nums;
}
.quiz-stat span { font-size: .8rem; color: var(--text-faint); }

.quiz-question-card { padding: 1.8rem; margin-bottom: 1.2rem; }
.quiz-question-card h3 { font-size: clamp(1.1rem, 2.4vw, 1.35rem); margin: 0; }

.quiz-answers { display: grid; grid-template-columns: 1fr 1fr; gap: .9rem; }
@media (max-width: 560px) { .quiz-answers { grid-template-columns: 1fr; } }
.quiz-answer {
  padding: 1rem 1.2rem;
  border-radius: var(--radius-m);
  background: var(--surface);
  border: 1px solid var(--border);
  text-align: left;
  font-weight: 600;
  transition: border-color .2s var(--ease), background .2s var(--ease), transform .15s var(--ease);
}
.quiz-answer:hover:not(:disabled) { border-color: var(--accent); background: var(--surface-strong); transform: translateY(-2px); }
.quiz-answer:disabled { cursor: default; }
.quiz-answer.is-correct { border-color: #2ecc71; background: color-mix(in srgb, #2ecc71 18%, var(--surface)); }
.quiz-answer.is-wrong { border-color: #ff5c5c; background: color-mix(in srgb, #ff5c5c 18%, var(--surface)); }

.quiz-gameover { padding: clamp(1.8rem, 5vw, 2.6rem); text-align: center; }
.quiz-gameover p { margin-bottom: 0; }
.quiz-new-best {
  display: inline-block; margin-top: .9rem;
  padding: .3rem .9rem; border-radius: 999px;
  background: var(--gradient); color: #08080d;
  font-weight: 700; font-size: .82rem;
}
/* `display: inline-block` above has the same specificity as the
   browser's own `[hidden] { display: none }` rule, and — being an
   author style — wins the tie regardless of source order, which
   silently defeated the `hidden` attribute. This restores it. */
.quiz-new-best[hidden] { display: none; }

/* ---------- 404 ---------- */
.error-page { min-height: 80vh; display: grid; place-items: center; text-align: center; padding-top: 6rem; }
.error-code { font-family: var(--font-display); font-size: clamp(5rem, 18vw, 9rem); font-weight: 800; line-height: 1; }
