/* ============================================================
   M360 — Spark  ·  Liquid Glass shared stylesheet
   ============================================================ */

/* ---------- Page transitions ----------
   Smooth cross-page fade/scale on navigation (Chromium MPA View Transitions);
   browsers without support simply navigate normally. */
@view-transition { navigation: auto; }
/* ONE canonical cross-page transition: a clean opacity cross-dissolve with the
   incoming page settling up a few px. Deliberately NO scale and NO blur — both
   make the full-page snapshot judder/flicker (and blur is expensive to animate),
   which read as the old "fluctuation". The outgoing page just fades; only the new
   one moves, so there's no fighting double-slide. Keep this the single source —
   do not re-declare ::view-transition or vt-* keyframes elsewhere. */
::view-transition-old(root) { animation: vt-out 0.26s cubic-bezier(0.4,0,1,1) both; }
::view-transition-new(root) { animation: vt-in 0.42s cubic-bezier(0.16,0.7,0.2,1) 0.04s both; }
@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; transform: translateY(9px); } to { opacity: 1; transform: none; } }
/* Let the incoming page own the frame: hold the old snapshot under the new as it
   fades, so you never see a flash of empty base between them. */
::view-transition-old(root) { z-index: 1; }
::view-transition-new(root) { z-index: 2; }
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* overflow-x:hidden ONLY on <html>, NOT <body>: putting it on <body> turned the
   body into a scroll container that doesn't scroll, which BROKE `position: sticky`
   on the topbar (it scrolled away instead of pinning). html still clips horizontal
   overflow, so the aurora blobs stay contained and the sticky topbar works. */
html { overflow-x: hidden; }
/* Force the vertical scrollbar to ALWAYS be present (overflow-y:scroll) so it can
   NEVER appear/disappear when a panel expands. When the page is short enough that
   opening the Updates panel pushes content past the viewport, the scrollbar would
   pop in, narrow the page, and shift the whole bar sideways — the "shift" Ram saw.
   overflow-y:scroll is honored by every browser incl. Atlas/Chromium (more
   reliable than scrollbar-gutter alone, which some builds ignore). Gutter kept as
   a backstop so the reserved space stays symmetric. */
html { overflow-y: scroll; scrollbar-gutter: stable; }
/* Paint the root the theme base immediately so a reload / same-page click never
   flashes the browser's default white canvas before our CSS applies. */
html { background: var(--base); }
:root { color-scheme: dark; }
:root[data-theme="light"] { color-scheme: light; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
input, textarea, select { font: inherit; color: inherit; }
a { color: inherit; text-decoration: none; }
img, svg { display: block; max-width: 100%; }

/* ---------- Tokens ---------- */
:root {
  /* Miniclip brand */
  --mc-red:        #e8472b;   /* primary action */
  --mc-red-hi:     #ff6243;
  --mc-blue:       #3d4dc7;   /* accent / data / secondary */
  --mc-blue-hi:    #5a6bff;
  /* aurora palette — repurposed to the Miniclip duotone (blue=cool, red=warm) so
     the whole system reads on-brand. Names kept to avoid churn across the app. */
  --aurora-purple: #4654db;   /* (Miniclip blue) */
  --aurora-orange: #e8472b;   /* (Miniclip red)  */
  --aurora-cyan:   #2bc4e8;   /* data teal */
  --aurora-pink:   #ff6a4d;   /* warm coral, supports red */
  --aurora-green:  #3ddc97;
  --base:          #080a14;
  --base-2:        #11141f;

  /* text tiers */
  --text-1: rgba(255, 255, 255, 0.96);
  --text-2: rgba(255, 255, 255, 0.68);
  --text-3: rgba(255, 255, 255, 0.44);
  --text-on-light: #0a0612;

  /* glass — tinted base UNDER the blur. Kept lighter + more translucent so the
     aurora visibly refracts through (reads as a lit frosted pane, not a dark card). */
  --glass-bg:        rgba(44, 42, 68, 0.55);
  --glass-bg-strong: rgba(34, 31, 54, 0.72);
  /* sticky bar must OBSCURE the content scrolling behind it — keep it opaque. */
  --glass-bg-bar:    rgba(18, 16, 30, 0.88);
  --glass-stroke:    rgba(255, 255, 255, 0.16);
  --glass-stroke-2:  rgba(255, 255, 255, 0.24);
  --glass-top-hi:    rgba(255, 255, 255, 0.42);
  --glass-bot-lo:    rgba(0, 0, 0, 0.35);
  /* backdrop filters — brightness + saturation lift so the aurora refracts through.
     Radii kept modest: heavy blur is the #1 scroll-jank cost and reads muddy. */
  --glass-filter:        blur(22px) saturate(210%) brightness(1.14) contrast(1.02);
  --glass-filter-strong: blur(30px) saturate(225%) brightness(1.18) contrast(1.03);
  --glass-sheen:         rgba(255, 255, 255, 0.22);

  /* radii */
  --r-sm: 10px;
  --r-md: 14px;
  --r-lg: 20px;
  --r-xl: 28px;
  --r-2xl: 36px;
  --r-pill: 999px;

  /* motion */
  --spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease:   cubic-bezier(0.2, 0.7, 0.2, 1);

  /* layout */
  --bar-h: 64px;
  --content-max: 1280px;
}

/* ---------- Type ---------- */
body {
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
    "Inter", "Helvetica Neue", Arial, sans-serif;
  font-size: 15px;
  line-height: 1.55;
  color: var(--text-1);
  background: var(--base);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  letter-spacing: -0.005em;
  min-height: 100vh;
  /* clears the fixed topbar (top:20 + 64 height = bottom ~84) so content starts below it */
  padding-top: 92px;
}

h1, h2, h3, h4 { margin: 0; letter-spacing: -0.02em; line-height: 1.1; }
h1 { font-size: 44px; font-weight: 640; }
h2 { font-size: 28px; font-weight: 620; }
h3 { font-size: 20px; font-weight: 600; }
h4 { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; }
p  { margin: 0; line-height: 1.6; color: var(--text-2); }

.eyebrow {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--text-3);
}

.mono {
  font-family: "SF Mono", ui-monospace, Menlo, Consolas, monospace;
  font-feature-settings: "ss01", "ss02";
}

.muted   { color: var(--text-2); }
.dim     { color: var(--text-3); }

.grad-text {
  background: linear-gradient(105deg, #ff7a5c 0%, #e8472b 38%, #5a6bff 72%, #3d4dc7 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* ============================================================
   AURORA WALLPAPER
   Layered radial blooms with slow drift; vignette pushes
   colour to the edges so text isn't fighting it.
   ============================================================ */

.aurora {
  position: fixed;
  inset: 0;
  z-index: -2;
  background: var(--base);
  overflow: hidden;
}
.aurora::before, .aurora::after,
.aurora .blob {
  content: "";
  position: absolute;
  border-radius: 50%;
  filter: blur(48px);
  opacity: 0.9;
  will-change: transform;
}
.aurora::before {
  width: 720px; height: 720px;
  left: -160px; top: -180px;
  background: radial-gradient(circle, var(--aurora-purple) 0%, transparent 65%);
  animation: drift-a 28s ease-in-out infinite alternate;
}
.aurora::after {
  width: 820px; height: 820px;
  right: -200px; top: -120px;
  background: radial-gradient(circle, var(--aurora-orange) 0%, transparent 60%);
  animation: drift-b 28s ease-in-out infinite alternate;
}
.aurora .blob.c {
  width: 720px; height: 720px;
  left: 16%; bottom: -240px;
  background: radial-gradient(circle, var(--aurora-cyan) 0%, transparent 62%);
  opacity: 0.72;
  animation: drift-c 32s ease-in-out infinite alternate;
}
.aurora .blob.p {
  width: 560px; height: 560px;
  right: 8%; bottom: -150px;
  background: radial-gradient(circle, var(--aurora-pink) 0%, transparent 62%);
  opacity: 0.68;
  animation: drift-d 36s ease-in-out infinite alternate;
}

/* Vignette — pushes colour away from the centre where text lives. */
.aurora-vignette {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(ellipse 86% 64% at 50% 44%, transparent 0%, rgba(10,6,18,0.22) 58%, rgba(10,6,18,0.7) 100%),
    linear-gradient(180deg, rgba(10,6,18,0.45) 0%, transparent 20%, transparent 80%, rgba(10,6,18,0.72) 100%);
}

/* fine grain noise — an ultra-subtle material so the base never reads as flat
   black/white. Overlaid everywhere (fixed, behind content). */
.aurora-grain {
  position: fixed; inset: 0; z-index: -1; pointer-events: none;
  opacity: 0.08; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.55 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}

/* ---- Perf modes (driven by perfGovernor in spark.js) ---- */
/* Lite mode (low-end / reduced-motion / measured-janky): freeze the aurora drift —
   the dominant continuous paint. Static blurred blobs composite from cache (near
   free) and never re-rasterise, so the page stays smooth and doesn't degrade over a
   long session. Pointer parallax/tilt/magnetic are disabled in JS. Look stays rich;
   it just doesn't drift. */
html.perf-lite .aurora::before,
html.perf-lite .aurora::after,
html.perf-lite .aurora .blob { animation: none !important; }
/* Tab hidden: pause every keyframe — nothing is visible, so stop burning GPU /
   battery (and halt any slow compositor build-up while the user is away). */
html.anim-hidden *, html.anim-hidden *::before, html.anim-hidden *::after {
  animation-play-state: paused !important;
}

/* Translate-only drift (NO scale): scaling a blurred layer forces the browser to
   re-rasterise the big 48px-blurred blob every frame — sustained GPU load that
   makes the page progressively janky on a long session (thermal throttling). With
   translate3d alone the layer is rasterised ONCE and only composited/moved, which
   is nearly free and stable over time. The motion still reads as a living aurora. */
@keyframes drift-a {
  0%   { transform: translate3d(0, 0, 0); }
  100% { transform: translate3d(120px, 80px, 0); }
}
@keyframes drift-b {
  0%   { transform: translate3d(0, 0, 0); }
  100% { transform: translate3d(-140px, 60px, 0); }
}
@keyframes drift-c {
  0%   { transform: translate3d(0, 0, 0); }
  100% { transform: translate3d(80px, -100px, 0); }
}
@keyframes drift-d {
  0%   { transform: translate3d(0, 0, 0); }
  100% { transform: translate3d(-90px, -60px, 0); }
}

/* ============================================================
   GLASS  —  tinted dark base + blur + edge weight
   ============================================================ */

.glass {
  /* A faint top→bottom sheen baked into the fill gives the pane dimensional frost
     even where the aurora behind is dark (content sits in the vignette) — so glass
     reads as glass, not a flat card. The token tint sits under it. */
  background:
    linear-gradient(180deg, rgba(255,255,255,0.07) 0%, rgba(255,255,255,0.015) 30%, rgba(255,255,255,0) 60%),
    var(--glass-bg);
  border: 1px solid var(--glass-stroke);
  border-radius: var(--r-xl);
  /* Real refraction — blur what's behind so the aurora bends through the pane.
     This is what makes it read as a slab of glass instead of a flat tinted card. */
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: var(--glass-filter);
  /* Beveled glass thickness: a bright top edge AND a bottom refraction edge (light
     exits the lower rim), a faint full inner ring for body, a soft inner top sheen,
     then a contact shadow + two soft float shadows for grounded depth. */
  box-shadow:
    inset 0 2px 0.5px var(--glass-top-hi),
    inset 0 -2px 2px rgba(255,255,255,0.16),
    inset 0 0 0 1px rgba(255,255,255,0.06),
    inset 0 24px 44px -28px rgba(255,255,255,0.26),
    0 2px 4px rgba(0,0,0,0.3),
    0 24px 50px -20px rgba(0,0,0,0.6),
    0 48px 100px -36px rgba(0,0,0,0.5);
  position: relative;
}

/* Liquid-glass SVG refraction was REMOVED for performance: an SVG filter inside
   backdrop-filter (url("#sparkLiquidGlass")) is one of the most expensive things to
   composite, and it was applied to every .glass surface (topbar, menus, panels) —
   re-rasterising each frame as the animated aurora drifted behind. The rich CSS
   blur + bevel above already reads as glass; the displacement was a subtle extra
   not worth the page-wide jank. */

.glass-strong {
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-stroke-2);
  border-radius: var(--r-xl);
  backdrop-filter: var(--glass-filter-strong);
  -webkit-backdrop-filter: var(--glass-filter-strong);
  box-shadow:
    inset 0 2px 0.5px rgba(255,255,255,0.6),
    inset 0 -1.5px 1px rgba(255,255,255,0.16),
    inset 0 0 0 1px rgba(255,255,255,0.05),
    inset 0 18px 32px -22px rgba(255,255,255,0.18),
    0 1px 1px rgba(0,0,0,0.3),
    0 26px 56px -20px rgba(0,0,0,0.6),
    0 50px 100px -34px rgba(0,0,0,0.55);
}

/* Liquid-glass sheen: a bright top edge fading down + a soft corner catch-light
   + a diagonal specular sweep + a faint lower lip. Reads as curved, refractive glass. */
.glass::after, .glass-strong::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background:
    linear-gradient(180deg, var(--glass-sheen) 0%, rgba(255,255,255,0.09) 11%, transparent 32%),
    radial-gradient(140% 92% at 12% -14%, rgba(255,255,255,0.26) 0%, transparent 42%),
    radial-gradient(120% 80% at 100% 114%, rgba(255,255,255,0.1) 0%, transparent 46%);
  mix-blend-mode: screen;
  opacity: 1;
  z-index: 1;
}

/* Signature liquid-glass rim: a thin refractive gradient edge that catches the
   aurora — purple→cyan→amber→pink, masked to a 1px ring. The premium "lit edge"
   from the reference glass kit. */
.glass::before,
.glass-strong::before,
.game-card::before,
.hero-frame::before,
.topbar::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  /* Neutral liquid-glass lens edge: a soft WHITE specular catch-light at the
     top-left (the real iOS-26/27 glass highlight), fading to nothing by mid-panel,
     with only a whisper of the Miniclip warm (red) returning at the bottom-right.
     No purple/pink — brand-neutral + premium. */
  background: linear-gradient(135deg,
    rgba(255,255,255,0.72) 0%,
    rgba(255,255,255,0.18) 11%,
    rgba(180,200,255,0.05) 34%,
    transparent 56%,
    rgba(255,150,110,0.05) 82%,
    rgba(255,110,80,0.16) 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  mix-blend-mode: screen;
  opacity: 0.92;
  pointer-events: none;
  z-index: 2;
}
.topbar { position: relative; }
.glass-strong::before { opacity: 0.95; }

/* ============================================================
   TOP BAR — sticky floating pill
   ============================================================ */

.topbar-wrap {
  /* FIXED (not sticky): sticky was breaking under the page's overflow setup and
     scrolling away. Fixed pins the bar to the viewport unconditionally and lets the
     content scroll BEHIND it (the centred pill is narrower than the viewport, so
     content is visible on either side as it passes under). Content is offset by
     `body { padding-top }` below so nothing hides under the bar. */
  position: fixed;
  top: 20px; left: 0; right: 0;
  z-index: 40;
  padding: 0 24px;
  display: flex;
  justify-content: center;
  pointer-events: none;
}
.topbar {
  pointer-events: auto;
  width: 100%;
  max-width: var(--content-max);
  height: var(--bar-h);
  padding: 0 14px 0 18px;
  border-radius: var(--r-pill);
  background: var(--glass-bg-bar);
  /* light blur only — the bar is opaque enough to obscure content, so it stays
     clean during scroll without a heavy per-frame re-rasterise. */
  backdrop-filter: blur(12px) saturate(150%);
  -webkit-backdrop-filter: blur(12px) saturate(150%);
  border: 1px solid var(--glass-stroke);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.52),
    inset 0 -1px 0 var(--glass-bot-lo),
    inset 0 0 0 1px rgba(255,255,255,0.03),
    0 18px 50px -10px rgba(0,0,0,0.55);
  display: flex;
  align-items: center;
  gap: 18px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 640;
  letter-spacing: -0.01em;
  font-size: 15.5px;
  white-space: nowrap;
  flex-shrink: 0;
}
.brand-name { white-space: nowrap; }
.brand-beta {
  margin-left: 6px; padding: 2px 7px; border-radius: 999px;
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: #c9b6f0; background: rgba(61, 77, 199,0.16); border: 1px solid rgba(61, 77, 199,0.32);
  align-self: center; line-height: 1;
}
.brand-mark {
  width: 28px; height: 28px;
  border-radius: 8px;
  /* Miniclip duotone — blue body with a red corner glow (no red↔blue blend, so no
     muddy purple). Mirrors the M-mark on the splash. */
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.5), transparent 46%),
    radial-gradient(circle at 82% 86%, #ff6243 0%, rgba(232,71,43,0) 56%),
    linear-gradient(150deg, #5a6bff 0%, #3344b8 100%);
  box-shadow:
    inset 0 1.5px 0 rgba(255,255,255,0.6),
    inset 0 -1px 2px rgba(0,0,0,0.3),
    inset 0 0 0 1px rgba(255,255,255,0.12),
    0 4px 14px rgba(61, 77, 199, 0.42),
    0 2px 10px rgba(232, 71, 43, 0.28);
}
/* Liquid-glass sheen on the Spark mark — a glossy diagonal catch-light over the
   duotone, like a bead of glass. Sits above the bolt at low screen-blend opacity. */
.brand-mark::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background:
    linear-gradient(152deg, rgba(255,255,255,0.55) 0%, rgba(255,255,255,0.14) 26%, transparent 48%),
    radial-gradient(120% 80% at 18% -10%, rgba(255,255,255,0.4), transparent 46%);
  mix-blend-mode: screen; opacity: 0.7; z-index: 3;
}
.brand-mark.lg::after, .brand-mark.xl::after { opacity: 0.6; }
.brand-mark.lg {
  width: 56px; height: 56px;
  border-radius: 16px;
  box-shadow:
    inset 0 1.5px 0 rgba(255,255,255,0.45),
    inset 0 -1.5px 0 rgba(0,0,0,0.25),
    0 12px 30px rgba(61, 77, 199, 0.45),
    0 0 0 0.5px rgba(255,255,255,0.1);
}
.brand-mark.xl {
  width: 76px; height: 76px;
  border-radius: 22px;
}

.nav {
  display: flex;
  align-items: center;
  gap: 2px;
  margin-left: 12px;
}
.nav a {
  padding: 8px 14px;
  border-radius: var(--r-pill);
  font-size: 13.5px;
  font-weight: 500;
  color: var(--text-2);
  white-space: nowrap;
  border: 1px solid transparent;
  transition: color 0.2s, background 0.2s, border-color 0.2s, box-shadow 0.25s;
}
.nav a:hover {
  color: var(--text-1);
  background: linear-gradient(180deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.04) 100%);
  border-color: rgba(255,255,255,0.08);
}
.nav a.active {
  color: var(--text-1);
  background: linear-gradient(180deg, rgba(255,255,255,0.14) 0%, rgba(255,255,255,0.06) 100%);
  border-color: rgba(255,255,255,0.14);
  backdrop-filter: blur(10px) saturate(160%);
  -webkit-backdrop-filter: blur(10px) saturate(160%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.22),
    inset 0 -1px 0 rgba(0,0,0,0.18),
    0 4px 12px -4px rgba(0,0,0,0.4);
}

.bar-spacer { flex: 1; }

.search {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 38px;
  padding: 0 14px;
  border-radius: var(--r-pill);
  background: linear-gradient(180deg, rgba(255,255,255,0.14) 0%, rgba(255,255,255,0.05) 100%);
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.24);
  width: 240px;
  color: var(--text-3);
  font-size: 13.5px;
  transition: background 0.2s, border-color 0.2s;
}
.search:hover { background: linear-gradient(180deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0.07) 100%); }
.search input {
  flex: 1; border: 0; background: transparent; outline: 0; color: var(--text-1);
  font-size: 13.5px;
}
.search input::placeholder { color: var(--text-3); }
.search kbd {
  font-family: inherit;
  font-size: 11px;
  padding: 2px 6px;
  border-radius: 5px;
  background: rgba(255,255,255,0.08);
  color: var(--text-3);
  border: 1px solid rgba(255,255,255,0.06);
}

.iconbtn {
  width: 38px; height: 38px;
  border-radius: var(--r-pill);
  display: grid; place-items: center;
  color: var(--text-2);
  background: linear-gradient(180deg, rgba(255,255,255,0.16) 0%, rgba(255,255,255,0.05) 100%);
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.28), 0 4px 12px -6px rgba(0,0,0,0.4);
  position: relative;
  transition: background 0.2s, color 0.2s, transform 0.3s var(--spring), border-color 0.2s;
}
.iconbtn:hover { background: linear-gradient(180deg, rgba(255,255,255,0.22) 0%, rgba(255,255,255,0.08) 100%); color: var(--text-1); border-color: rgba(255,255,255,0.22); }
.iconbtn .dot {
  position: absolute; top: 8px; right: 9px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--aurora-orange);
  box-shadow: 0 0 0 2px rgba(15,15,25,0.9), 0 0 8px var(--aurora-orange);
}

.avatar {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--aurora-cyan), var(--aurora-purple));
  display: grid; place-items: center;
  font-size: 12px; font-weight: 640; color: white;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.3),
    0 4px 10px rgba(0,0,0,0.35);
  flex-shrink: 0;
}
.avatar.sm { width: 22px; height: 22px; font-size: 10px; }
.avatar.tiny { width: 18px; height: 18px; font-size: 9px; }
.avatar.lg { width: 40px; height: 40px; font-size: 14px; }
.avatar.warm { background: linear-gradient(135deg, var(--aurora-orange), var(--aurora-pink)); }
.avatar.green { background: linear-gradient(135deg, var(--aurora-cyan), var(--aurora-green)); }
.avatar.violet { background: linear-gradient(135deg, var(--aurora-pink), var(--aurora-purple)); }

/* Account menu (avatar dropdown) — email + sign out. */
.user-menu {
  /* !important: the menu also carries `.glass`, and a later `.glass{position:relative}`
     rule (needed for its ::before/::after) was overriding this — the menu rendered
     as a full-width in-flow block at the bottom of the page instead of a fixed
     dropdown. Force fixed so it always anchors under the avatar. */
  position: fixed !important; z-index: 1000; min-width: 220px; width: max-content; max-width: 280px;
  padding: 12px; border-radius: var(--r-lg);
  animation: um-in 0.18s var(--ease) both;
}
@keyframes um-in { from { opacity: 0; transform: translateY(-6px) scale(0.98); } }
.user-menu .um-email { font-size: 13px; font-weight: 600; color: var(--text-1); padding: 4px 8px 2px; word-break: break-all; }
.user-menu .um-role { font-size: 10.5px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--aurora-cyan); padding: 0 8px 4px; }
.user-menu .um-sep { height: 1px; margin: 8px 4px; background: var(--glass-stroke); }
.user-menu .um-item {
  display: flex; align-items: center; gap: 8px; width: 100%;
  height: 38px; padding: 0 12px; border-radius: var(--r-md);
  font-size: 13.5px; font-weight: 560; color: var(--text-1); text-align: left;
  background: transparent; cursor: pointer; transition: background 0.15s;
}
.user-menu .um-item:hover { background: rgba(255,255,255,0.08); }
.user-menu .um-signout { color: #ff8a72; }
.user-menu .um-ver { margin-top: 6px; padding: 7px 8px 3px; border-top: 1px solid var(--glass-stroke); font-size: 10.5px; font-weight: 600; letter-spacing: 0.02em; color: var(--text-3); text-align: center; }
:root[data-theme="light"] .user-menu .um-item:hover { background: rgba(20,18,40,0.06); }

/* ============================================================
   BUTTONS — solid for confident tap targets
   ============================================================ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 44px;
  padding: 0 20px;
  border-radius: var(--r-pill);
  font-size: 14.5px;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--text-1);
  background: linear-gradient(180deg, rgba(255,255,255,0.16) 0%, rgba(255,255,255,0.07) 52%, rgba(255,255,255,0.05) 100%);
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.28),
    inset 0 -1px 0 rgba(0,0,0,0.18),
    0 6px 16px -6px rgba(0,0,0,0.45);
  transition: transform 0.25s var(--spring), background 0.2s, box-shadow 0.2s, border-color 0.2s;
  white-space: nowrap;
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.btn:hover {
  background: linear-gradient(180deg, rgba(255,255,255,0.22) 0%, rgba(255,255,255,0.1) 52%, rgba(255,255,255,0.07) 100%);
  border-color: rgba(255,255,255,0.24);
  transform: translateY(-1px);
}
.btn:active { transform: translateY(0); }

/* Universal wet gloss: a bright sheen across the top half of every pill button
   (the signature glossy-glass highlight from the reference kit). */
.btn:not(.btn-ghost)::before {
  content: "";
  position: absolute;
  left: 1px; right: 1px; top: 1px;
  height: 50%;
  border-radius: inherit;
  background: linear-gradient(180deg, rgba(255,255,255,0.5) 0%, rgba(255,255,255,0.14) 55%, transparent 100%);
  opacity: 0.8;
  pointer-events: none;
  z-index: -1;
}

.btn-ghost {
  background: transparent;
  border-color: rgba(255,255,255,0.08);
  color: var(--text-2);
}
.btn-ghost:hover { background: rgba(255,255,255,0.05); color: var(--text-1); }

.btn-primary {
  color: white;
  background:
    linear-gradient(135deg, #ff6243 0%, #e8472b 58%, #cf3c20 100%);
  border: 1px solid rgba(255,255,255,0.18);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.35),
    inset 0 -1px 0 rgba(0,0,0,0.2),
    0 10px 24px -6px rgba(232, 71, 43, 0.5),
    0 4px 10px -2px rgba(61, 77, 199, 0.4);
}
.btn-primary:hover {
  transform: translateY(-2px);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.4),
    inset 0 -1px 0 rgba(0,0,0,0.2),
    0 14px 32px -6px rgba(232, 71, 43, 0.6),
    0 6px 14px -2px rgba(61, 77, 199, 0.5);
}

.btn-success {
  color: white;
  background: linear-gradient(135deg, #4be0a8 0%, #34c2e0 100%);
  border: 1px solid rgba(255,255,255,0.2);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.35),
    0 10px 24px -6px rgba(75, 224, 168, 0.45);
}

/* Glossy CTA: a soft specular catch-light in the top-left corner, on top of the
   universal .btn gloss band. */
.btn-primary::after, .btn-success::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(120% 80% at 18% -20%, rgba(255,255,255,0.4), transparent 50%);
  pointer-events: none;
  z-index: -1;
}

.btn-lg { height: 52px; padding: 0 26px; font-size: 15px; border-radius: var(--r-pill); }
.btn-sm { height: 32px; padding: 0 12px; font-size: 12.5px; gap: 6px; }
.btn-block { width: 100%; }

/* Floating action button — bottom-right primary */
.fab {
  position: fixed;
  right: 32px;
  bottom: 32px;
  z-index: 30;
  height: 56px;
  padding: 0 24px 0 18px;
  font-size: 14.5px;
  font-weight: 640;
  display: inline-flex;
  align-items: center;
  gap: 11px;
  border-radius: var(--r-pill);
  color: white;
  isolation: isolate;
  /* True liquid glass: a translucent brand tint that lets the blurred page show
     through, a bright top rim, and a soft grounded shadow for clean separation
     from cards below — no harsh "ring". */
  background:
    radial-gradient(130% 96% at 26% -10%, rgba(255,180,150,0.55), transparent 56%),
    linear-gradient(135deg, #ff6a48 0%, #e8472b 56%, #d23f23 100%);
  backdrop-filter: blur(16px) saturate(160%);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  border: 1px solid rgba(255,255,255,0.4);
  box-shadow:
    inset 0 1.5px 0 rgba(255,255,255,0.6),
    inset 0 -3px 8px rgba(120,20,0,0.28),
    inset 0 0 0 1px rgba(255,120,90,0.35),
    0 2px 6px rgba(0,0,0,0.25),
    0 18px 44px -10px rgba(232, 71, 43, 0.5),
    0 8px 22px -6px rgba(0,0,0,0.45);
  transition: transform 0.3s var(--spring), box-shadow 0.35s var(--ease);
}
/* Glossy highlight sweep across the top third — the "liquid" sheen. */
.fab::before {
  content: "";
  position: absolute; left: 3px; right: 3px; top: 2px; height: 46%;
  border-radius: var(--r-pill);
  background: linear-gradient(180deg, rgba(255,255,255,0.42), rgba(255,255,255,0));
  pointer-events: none;
}
/* Separation halo: a soft glowing layer BEHIND the button — a gentle brand bloom
   over a faint dark grounding — so it lifts cleanly off the thumbnails below. */
.fab::after {
  content: "";
  position: absolute; inset: -22px; z-index: -1;
  border-radius: var(--r-pill);
  background:
    radial-gradient(closest-side, rgba(255,90,60,0.4), rgba(232,71,43,0.16) 56%, transparent 74%),
    radial-gradient(closest-side, rgba(8,5,16,0.26), transparent 70%);
  filter: blur(16px);
  pointer-events: none;
}
:root[data-theme="light"] .fab::after {
  background:
    radial-gradient(closest-side, rgba(255,90,60,0.34), rgba(232,71,43,0.14) 56%, transparent 74%),
    radial-gradient(closest-side, rgba(40,20,20,0.12), transparent 72%);
}

/* ---- Shared mechanic-motif poster (gallery cards + game detail) ---- */
.motif { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.motif svg { width: 100%; height: 100%; display: block; }
/* Keep motif line-art crisp and THIN at any render size: stroke widths are treated
   as display pixels, not scaled with the viewBox (the "thin line, clear style" look). */
.motif svg path, .motif svg circle, .motif svg rect,
.motif svg line, .motif svg polyline, .motif svg polygon { vector-effect: non-scaling-stroke; }
/* Muted, professional single-hue thumbnail backgrounds — one restrained tone
   each, a soft off-centre glow over a deep base; white motif reads cleanly. */
.th1 { background: radial-gradient(ellipse at 32% 30%, rgba(120,104,180,0.40) 0%, transparent 62%), linear-gradient(140deg, #1a1630, #0e0b1a); }
.th2 { background: radial-gradient(ellipse at 68% 32%, rgba(86,120,168,0.40) 0%, transparent 62%), linear-gradient(140deg, #121c2e, #080d18); }
.th3 { background: radial-gradient(ellipse at 40% 34%, rgba(176,98,128,0.36) 0%, transparent 62%), linear-gradient(140deg, #241420, #150b13); }
.th4 { background: radial-gradient(ellipse at 30% 32%, rgba(78,150,134,0.36) 0%, transparent 62%), linear-gradient(140deg, #102420, #081512); }
.th5 { background: radial-gradient(ellipse at 70% 32%, rgba(178,120,92,0.34) 0%, transparent 62%), linear-gradient(140deg, #241710, #150d08); }
.th6 { background: radial-gradient(ellipse at 36% 70%, rgba(132,104,184,0.38) 0%, transparent 62%), linear-gradient(140deg, #16122a, #0c0918); }
.th7 { background: radial-gradient(ellipse at 50% 60%, rgba(180,142,86,0.34) 0%, transparent 62%), linear-gradient(140deg, #221a0e, #140f08); }
.th8 { background: radial-gradient(ellipse at 34% 34%, rgba(82,140,156,0.38) 0%, transparent 62%), linear-gradient(140deg, #0e2228, #071417); }
.th9 { background: radial-gradient(ellipse at 50% 46%, rgba(168,98,110,0.34) 0%, transparent 64%), linear-gradient(140deg, #20121a, #130a10); }
.fab:hover {
  transform: translateY(-3px) scale(1.02);
  box-shadow:
    inset 0 1.5px 0 rgba(255,255,255,0.6),
    inset 0 -2px 6px rgba(0,0,0,0.18),
    0 2px 6px rgba(0,0,0,0.3),
    0 26px 56px -10px rgba(232, 71, 43, 0.55),
    0 12px 30px -6px rgba(0,0,0,0.55);
}
:root[data-theme="light"] .fab {
  border-color: rgba(255,255,255,0.7);
  box-shadow:
    inset 0 1.5px 0 rgba(255,255,255,0.7),
    inset 0 -2px 6px rgba(0,0,0,0.1),
    0 2px 8px rgba(40,20,60,0.18),
    0 18px 44px -10px rgba(255, 90, 130, 0.4),
    0 8px 22px -6px rgba(40,20,60,0.2);
}
.fab .plus {
  width: 28px; height: 28px;
  border-radius: 50%;
  background: rgba(255,255,255,0.18);
  display: grid; place-items: center;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.3);
}
/* Subtle travelling border shimmer — a soft highlight glides continuously around
   the FAB's rim (a masked conic light whose angle animates). Premium, restrained. */
@property --fab-ang { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
.fab-edge {
  position: absolute; inset: 0; border-radius: inherit;
  padding: 1.4px;
  background: conic-gradient(from var(--fab-ang),
    transparent 0deg,
    transparent 58%,
    rgba(255,255,255,0.35) 70%,
    rgba(255,255,255,0.95) 80%,
    rgba(190,224,255,0.9) 86%,
    transparent 96%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  mix-blend-mode: screen;
  opacity: 0.85;
  pointer-events: none;
  animation: fab-edge-travel 4.8s linear infinite;
}
@keyframes fab-edge-travel { to { --fab-ang: 360deg; } }
.fab:hover .fab-edge { opacity: 1; animation-duration: 2.6s; }
@media (prefers-reduced-motion: reduce) { .fab-edge { animation: none; opacity: 0.5; } }

/* ============================================================
   INPUTS
   ============================================================ */

.field {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.field label {
  font-size: 12.5px;
  font-weight: 540;
  color: var(--text-2);
  letter-spacing: 0.01em;
}
.input, .textarea, .select {
  width: 100%;
  height: 48px;
  padding: 0 16px;
  border-radius: var(--r-md);
  background: linear-gradient(180deg, rgba(255,255,255,0.14) 0%, rgba(255,255,255,0.05) 100%);
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.3),
    inset 0 -1px 0 rgba(0,0,0,0.18),
    0 4px 14px -6px rgba(0,0,0,0.4);
  color: var(--text-1);
  font-size: 14.5px;
  outline: 0;
  transition: border-color 0.2s, box-shadow 0.2s, background 0.2s;
}
.input::placeholder, .textarea::placeholder { color: var(--text-3); }
/* Textareas top-align by default and looked flush to the top edge — give them
   balanced vertical padding so short content reads vertically centred. */
textarea.input, .textarea, .fb-textarea { height: auto; min-height: 52px; line-height: 1.55; padding-top: 14px; padding-bottom: 14px; }
.input:hover, .textarea:hover, .select:hover {
  background: linear-gradient(180deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0.07) 100%);
  border-color: rgba(255,255,255,0.2);
}
.input:focus, .textarea:focus, .select:focus {
  border-color: rgba(74, 90, 224, 0.6);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.32),
    0 0 0 4px rgba(61, 77, 199, 0.22),
    0 6px 18px -6px rgba(61, 77, 199, 0.3);
  background: linear-gradient(180deg, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.08) 100%);
}
.textarea { height: auto; padding: 14px 16px; resize: vertical; min-height: 96px; line-height: 1.55; }

.input-icon {
  position: relative;
}
.input-icon svg {
  position: absolute; left: 16px; top: 50%; transform: translateY(-50%);
  color: var(--text-3); pointer-events: none;
}
.input-icon .input { padding-left: 44px; }

/* ============================================================
   PILLS, CHIPS, BADGES
   ============================================================ */

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  padding: 0 13px;
  border-radius: var(--r-pill);
  font-size: 12.5px;
  font-weight: 540;
  color: var(--text-2);
  background: linear-gradient(180deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.04) 100%);
  border: 1px solid rgba(255,255,255,0.1);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.18);
  white-space: nowrap;
  transition: background 0.2s, color 0.2s, border-color 0.2s, box-shadow 0.2s;
  cursor: pointer;
}
.chip:hover { background: linear-gradient(180deg, rgba(255,255,255,0.16) 0%, rgba(255,255,255,0.07) 100%); color: var(--text-1); }
.chip.active {
  color: #fff;
  background: linear-gradient(135deg, rgba(255,98,67,0.9) 0%, rgba(232,71,43,0.9) 60%, rgba(207,60,32,0.92) 100%);
  border-color: rgba(255,255,255,0.3);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.4),
    inset 0 -1px 0 rgba(0,0,0,0.15),
    0 6px 16px -6px rgba(232, 71, 43,0.5),
    0 3px 8px -2px rgba(61, 77, 199,0.4);
}
.chip svg { opacity: 0.85; }

.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 22px;
  padding: 0 8px;
  border-radius: 6px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--text-1);
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.06);
  white-space: nowrap;
}
.badge.dot::before {
  content: "";
  width: 6px; height: 6px; border-radius: 50%;
  background: currentColor;
}
.badge.tag { color: var(--text-3); background: rgba(255,255,255,0.05); border-color: rgba(255,255,255,0.07); text-transform: lowercase; font-weight: 540; }
.badge.tag.dot::before { background: rgba(160,150,210,0.55); }
:root[data-theme="light"] .badge.tag { color: var(--text-2); }
.badge.phaser  { color: #ffaf5c; background: rgba(255,122,89,0.14); border-color: rgba(255,122,89,0.22); }
.badge.three   { color: #c79bff; background: rgba(61, 77, 199,0.16); border-color: rgba(61, 77, 199,0.26); }
.badge.pixi    { color: #d9a0b8; background: rgba(200,130,160,0.14); border-color: rgba(200,130,160,0.24); }
.badge.canvas  { color: #7be3ff; background: rgba(52,224,255,0.12); border-color: rgba(52,224,255,0.22); }
.badge.html    { color: #b8e8a0; background: rgba(140,220,120,0.12); border-color: rgba(140,220,120,0.22); }

.version-pill {
  display: inline-flex;
  align-items: center;
  font-size: 11.5px;
  font-weight: 640;
  letter-spacing: 0.02em;
  height: 24px;
  padding: 0 10px;
  border-radius: var(--r-pill);
  color: var(--text-1);
  /* opaque enough to read without a blur — a per-card backdrop-filter here was a
     scroll-repaint cost (always-visible over each thumbnail). */
  background: rgba(18, 14, 28, 0.86);
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.18);
}
.version-pill.current {
  color: white;
  background: linear-gradient(135deg, rgba(255,122,89,0.95), rgba(61, 77, 199,0.95));
  border-color: rgba(255,255,255,0.3);
}

/* ============================================================
   LAYOUT HELPERS
   ============================================================ */

.page {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 8px 24px 120px;   /* top offset now comes from body padding-top (fixed bar) */
}

.flex { display: flex; }
.flex-col { display: flex; flex-direction: column; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.gap-2 { gap: 8px; } .gap-3 { gap: 12px; } .gap-4 { gap: 16px; }
.gap-5 { gap: 20px; } .gap-6 { gap: 24px; } .gap-8 { gap: 32px; }
.mt-2 { margin-top: 8px; } .mt-4 { margin-top: 16px; }
.mt-6 { margin-top: 24px; } .mt-8 { margin-top: 32px; }

/* ============================================================
   SCREEN-SPECIFIC bits live in each .html so this file
   stays small — but we share a couple of common patterns.
   ============================================================ */

/* Section header bar */
.section-head {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: 20px;
  margin: 8px 0 20px;
}
.section-head h1 .accent-dot {
  display: inline-block;
  width: 10px; height: 10px;
  border-radius: 50%;
  margin-left: 6px;
  margin-bottom: 4px;
  vertical-align: middle;
  background: var(--aurora-orange);
  box-shadow: 0 0 14px var(--aurora-orange);
}

.summary-line {
  color: var(--text-2);
  font-size: 14.5px;
  margin-top: 8px;
}

/* utility scroll-snap chip row */
.chip-row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
}

/* Tip / status link */
.status-link {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 12.5px; color: var(--text-3);
}
.status-link .pulse {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--aurora-green);
  box-shadow: 0 0 0 0 rgba(61,220,151,0.6);
  animation: pulse 2.4s ease-out infinite;
}
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(61,220,151,0.55); }
  70%  { box-shadow: 0 0 0 10px rgba(61,220,151,0); }
  100% { box-shadow: 0 0 0 0 rgba(61,220,151,0); }
}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 1120px) {
  /* keyboard hint is decorative — drop it before the bar gets tight */
  .search kbd { display: none; }
  .nav a { padding: 8px 11px; }
}
@media (max-width: 1000px) {
  .nav { display: none; }
}
@media (max-width: 900px) {
  h1 { font-size: 32px; }
  h2 { font-size: 22px; }
  .topbar-wrap { top: 12px; padding: 0 12px; }
  .topbar { height: 56px; padding: 0 10px 0 14px; gap: 10px; }
  .search { width: 200px; }
  body { padding-top: 76px; }   /* shorter bar on mobile (12 + 56) */
  .page { padding: 8px 16px 100px; }
  .fab { right: 16px; bottom: 16px; height: 50px; padding: 0 18px 0 14px; }
}
@media (max-width: 680px) {
  .search { width: 150px; }
}
@media (max-width: 560px) {
  .search { display: none; }
  .brand .brand-name { display: none; }
}

/* ============================================================
   THEME — smooth cross-fade between light & dark
   The dark tokens above are the default. Light overrides below.
   ============================================================ */

html.theme-anim,
html.theme-anim body,
html.theme-anim .glass,
html.theme-anim .glass-strong,
html.theme-anim .topbar,
html.theme-anim .game-card,
html.theme-anim .index-card,
html.theme-anim .vrow,
html.theme-anim .btn,
html.theme-anim .chip,
html.theme-anim .badge,
html.theme-anim .input,
html.theme-anim .select,
html.theme-anim .textarea {
  transition: background-color 0.45s var(--ease), color 0.45s var(--ease),
    border-color 0.45s var(--ease), box-shadow 0.45s var(--ease) !important;
}

:root[data-theme="light"] {
  --aurora-purple: #4a5ae0;
  --aurora-orange: #e8472b;
  --aurora-cyan:   #2bb6dc;
  --aurora-pink:   #ff6a4d;
  --aurora-green:  #2bbf85;
  /* A cooler, slightly deeper grey base so white glass panels visibly separate
     from the page instead of white-on-white. */
  --base:          #e3e6ef;
  --base-2:        #eef0f7;

  --text-1: rgba(16, 14, 30, 0.96);
  --text-2: rgba(26, 22, 44, 0.66);
  --text-3: rgba(34, 30, 54, 0.48);
  --text-on-light: #ffffff;

  /* More opaque, faintly cool-tinted glass + firmer strokes → clear panel edges. */
  --glass-bg:        rgba(255, 255, 255, 0.74);
  --glass-bg-strong: rgba(255, 255, 255, 0.86);
  --glass-bg-bar:    rgba(255, 255, 255, 0.9);
  --glass-stroke:    rgba(20, 18, 40, 0.13);
  --glass-stroke-2:  rgba(20, 18, 40, 0.2);
  --glass-top-hi:    rgba(255, 255, 255, 0.95);
  --glass-bot-lo:    rgba(20, 18, 40, 0.06);
  --glass-filter:        blur(30px) saturate(150%) brightness(1.03);
  --glass-filter-strong: blur(40px) saturate(160%) brightness(1.04);
  --glass-sheen:         rgba(255, 255, 255, 0.55);
}

:root[data-theme="light"] .glass,
:root[data-theme="light"] .game-card,
:root[data-theme="light"] .index-card {
  box-shadow:
    inset 0 1.5px 0.5px rgba(255,255,255,0.95),
    inset 0 -1.5px 1px rgba(255,255,255,0.6),
    inset 0 0 0 1px rgba(255,255,255,0.42),
    0 1px 1px rgba(40,36,80,0.06),
    0 18px 40px -16px rgba(40,36,80,0.2),
    0 40px 84px -30px rgba(40,36,80,0.2);
}
:root[data-theme="light"] .glass-strong {
  box-shadow:
    inset 0 2px 0.5px rgba(255,255,255,0.98),
    inset 0 -1.5px 1px rgba(255,255,255,0.65),
    inset 0 0 0 1px rgba(255,255,255,0.5),
    0 1px 1px rgba(40,36,80,0.07),
    0 26px 56px -20px rgba(40,36,80,0.24),
    0 52px 104px -34px rgba(40,36,80,0.22);
}
:root[data-theme="light"] .topbar {
  box-shadow:
    inset 0 1px 0 var(--glass-top-hi),
    0 16px 44px -14px rgba(40, 36, 80, 0.26);
}

/* Light mode: screen-blend rims vanish on white, so paint a softer coloured edge
   with normal blend. Keeps the lit-glass character without going neon. */
:root[data-theme="light"] .glass::before,
:root[data-theme="light"] .glass-strong::before,
:root[data-theme="light"] .game-card::before,
:root[data-theme="light"] .hero-frame::before,
:root[data-theme="light"] .topbar::before {
  background: linear-gradient(135deg,
    rgba(74,90,224,0.32) 0%,
    rgba(74,90,224,0.08) 18%,
    transparent 48%,
    rgba(255,140,100,0.06) 80%,
    rgba(232,71,43,0.26) 100%);
  mix-blend-mode: normal;
  opacity: 0.62;
}
:root[data-theme="light"] .glass-strong::before { opacity: 0.7; }

/* lighter aurora blobs + light vignette */
:root[data-theme="light"] .aurora::before { opacity: 0.42; }
:root[data-theme="light"] .aurora::after  { opacity: 0.42; }
:root[data-theme="light"] .aurora .blob.c { opacity: 0.34; }
:root[data-theme="light"] .aurora .blob.p { opacity: 0.32; }
:root[data-theme="light"] .aurora-grain { opacity: 0.055; mix-blend-mode: multiply; }
:root[data-theme="light"] .aurora-vignette {
  background:
    radial-gradient(ellipse 80% 60% at 50% 45%, transparent 0%, rgba(236,238,251,0.45) 55%, rgba(236,238,251,0.85) 100%),
    linear-gradient(180deg, rgba(236,238,251,0.6) 0%, transparent 18%, transparent 78%, rgba(236,238,251,0.85) 100%);
}

/* light: flip the "white film" chrome to ink film so it reads on light glass */
:root[data-theme="light"] .nav a:hover { background: rgba(20,18,40,0.05); }
:root[data-theme="light"] .nav a.active { background: rgba(20,18,40,0.07); box-shadow: inset 0 1px 0 rgba(255,255,255,0.6); }
:root[data-theme="light"] .search { background: rgba(20,18,40,0.04); border-color: rgba(20,18,40,0.07); }
:root[data-theme="light"] .search:hover { background: rgba(20,18,40,0.06); }
:root[data-theme="light"] .search kbd { background: rgba(20,18,40,0.07); border-color: rgba(20,18,40,0.06); }
:root[data-theme="light"] .iconbtn { background: rgba(20,18,40,0.04); border-color: rgba(20,18,40,0.08); }
:root[data-theme="light"] .iconbtn:hover { background: rgba(20,18,40,0.08); }
:root[data-theme="light"] .iconbtn .dot { box-shadow: 0 0 0 2px rgba(255,255,255,0.95), 0 0 8px var(--aurora-orange); }
:root[data-theme="light"] .btn {
  background: linear-gradient(180deg, rgba(255,255,255,0.92) 0%, rgba(255,255,255,0.7) 100%);
  border-color: rgba(20,18,40,0.1);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.9),
    inset 0 -1px 0 rgba(20,18,40,0.05),
    0 6px 16px -8px rgba(40,36,80,0.25);
  color: var(--text-1);
}
:root[data-theme="light"] .btn:hover {
  background: linear-gradient(180deg, #fff 0%, rgba(255,255,255,0.82) 100%);
  border-color: rgba(20,18,40,0.16);
}
:root[data-theme="light"] .btn:not(.btn-ghost)::before { opacity: 0.5; }
:root[data-theme="light"] .btn-ghost { background: transparent; border-color: rgba(20,18,40,0.1); }
:root[data-theme="light"] .btn-ghost:hover { background: rgba(20,18,40,0.05); }
/* Keep the coloured CTAs coloured in light mode (the generic .btn light rule
   above would otherwise flatten them to grey with invisible white text). */
:root[data-theme="light"] .btn-primary,
:root[data-theme="light"] .btn-success {
  color: #fff;
  border-color: rgba(255,255,255,0.45);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.45),
    inset 0 -1px 0 rgba(0,0,0,0.12),
    0 10px 24px -6px rgba(232, 71, 43,0.45),
    0 4px 12px -2px rgba(61, 77, 199,0.4);
}
:root[data-theme="light"] .btn-primary {
  background: linear-gradient(135deg, #ff6243 0%, #e8472b 58%, #cf3c20 100%);
}
:root[data-theme="light"] .btn-success {
  background: linear-gradient(135deg, #34e0ff 0%, #4be0a8 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.45),
    inset 0 -1px 0 rgba(0,0,0,0.12),
    0 10px 24px -6px rgba(52,224,255,0.45);
}
:root[data-theme="light"] .chip { background: linear-gradient(180deg, rgba(255,255,255,0.8) 0%, rgba(255,255,255,0.55) 100%); border-color: rgba(20,18,40,0.1); box-shadow: inset 0 1px 0 rgba(255,255,255,0.9); color: var(--text-2); }
:root[data-theme="light"] .chip:hover { background: #fff; color: var(--text-1); }
/* active chip keeps the brand gradient (defined in the base rule) — reads on light too */
:root[data-theme="light"] .badge { background: rgba(20,18,40,0.06); border-color: rgba(20,18,40,0.08); }
:root[data-theme="light"] .input,
:root[data-theme="light"] .textarea,
:root[data-theme="light"] .select {
  background: rgba(255,255,255,0.55);
  border-color: rgba(20,18,40,0.1);
  box-shadow: inset 0 1px 2px rgba(20,18,40,0.04);
}
:root[data-theme="light"] .input:hover,
:root[data-theme="light"] .textarea:hover,
:root[data-theme="light"] .select:hover { background: rgba(255,255,255,0.72); }
:root[data-theme="light"] .input:focus,
:root[data-theme="light"] .textarea:focus,
:root[data-theme="light"] .select:focus {
  background: rgba(255,255,255,0.85);
  border-color: rgba(61, 77, 199,0.5);
  box-shadow: 0 0 0 4px rgba(61, 77, 199,0.16);
}

/* light: patch per-screen dark fills (defined inline in pages) */
:root[data-theme="light"] .dropzone { background: rgba(255,255,255,0.46); border-color: rgba(20,18,40,0.18); }
:root[data-theme="light"] .file-row,
:root[data-theme="light"] .stat,
:root[data-theme="light"] .activity-spark,
:root[data-theme="light"] .qr-link,
:root[data-theme="light"] .copy-row,
:root[data-theme="light"] .engine-row,
:root[data-theme="light"] .tags-input,
:root[data-theme="light"] .segmented {
  background: rgba(255,255,255,0.5);
  border-color: rgba(20,18,40,0.08);
}
:root[data-theme="light"] .qr-link button,
:root[data-theme="light"] .tags-input .t,
:root[data-theme="light"] .segmented .seg.on { background: rgba(20,18,40,0.07); }
:root[data-theme="light"] .sso-btn,
:root[data-theme="light"] .reaction,
:root[data-theme="light"] .share-btn { background: rgba(20,18,40,0.05); border-color: rgba(20,18,40,0.09); }
:root[data-theme="light"] .sso-btn:hover,
:root[data-theme="light"] .reaction:hover,
:root[data-theme="light"] .share-btn:hover { background: rgba(20,18,40,0.09); }
:root[data-theme="light"] .vrow {
  box-shadow: inset 0 1px 0 var(--glass-top-hi), 0 8px 22px -10px rgba(40,36,80,0.2);
}
:root[data-theme="light"] .vrow::before { border-color: rgba(255,255,255,0.9); }
:root[data-theme="light"] .version-pill { background: rgba(255,255,255,0.78); color: var(--text-1); border-color: rgba(20,18,40,0.12); }

/* ============================================================
   STACK BADGES — colour-coded engine identity
   ============================================================ */
.badge.react   { color: #4cc2e8; background: rgba(76,194,232,0.14); border-color: rgba(76,194,232,0.26); }
.badge.js      { color: #e6c34a; background: rgba(230,195,74,0.14); border-color: rgba(230,195,74,0.26); }
.badge.html5   { color: #ff9460; background: rgba(255,122,89,0.14); border-color: rgba(255,122,89,0.24); }
:root[data-theme="light"] .badge.phaser { color: #c4601f; }
:root[data-theme="light"] .badge.three  { color: #6b3fd4; }
:root[data-theme="light"] .badge.pixi   { color: #c43a6b; }
:root[data-theme="light"] .badge.canvas { color: #1f86b0; }
:root[data-theme="light"] .badge.html   { color: #3f8f2a; }
:root[data-theme="light"] .badge.react  { color: #1f86b0; }
:root[data-theme="light"] .badge.js     { color: #9a7e15; }
:root[data-theme="light"] .badge.html5  { color: #c4601f; }

/* ============================================================
   THEME TOGGLE — liquid-glass sliding switch
   ============================================================ */
.theme-toggle {
  position: relative;
  width: 64px; height: 34px;
  flex-shrink: 0;
  padding: 0;
  border-radius: var(--r-pill);
  background: rgba(255,255,255,0.05);
  border: 1px solid var(--glass-stroke-2);
  box-shadow: inset 0 1px 0 var(--glass-top-hi), inset 0 -1px 0 var(--glass-bot-lo);
  cursor: pointer;
  overflow: hidden;
  transition: background 0.3s var(--ease);
}
:root[data-theme="light"] .theme-toggle { background: rgba(20,18,40,0.05); }
.theme-toggle .tt-thumb {
  position: absolute; top: 3px; left: 3px;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: linear-gradient(135deg, #2a2440, #14101f);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.25), 0 4px 10px rgba(0,0,0,0.45);
  transition: transform 0.5s var(--spring), background 0.4s var(--ease);
  z-index: 2;
}
:root[data-theme="light"] .theme-toggle .tt-thumb {
  transform: translateX(30px);
  background: linear-gradient(135deg, #fff3d6, #ffd479);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.7), 0 4px 12px rgba(255,180,80,0.5);
}
.theme-toggle svg {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 14px; height: 14px;
  transition: opacity 0.3s var(--ease);
}
.theme-toggle .tt-moon { right: 9px; color: var(--text-2); opacity: 1; }
.theme-toggle .tt-sun  { left: 9px; color: #e8a93a; opacity: 0; }
:root[data-theme="light"] .theme-toggle .tt-moon { opacity: 0; }
:root[data-theme="light"] .theme-toggle .tt-sun  { opacity: 1; }
.theme-toggle.floating {
  position: fixed; top: 22px; right: 22px; z-index: 60;
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  background: var(--glass-bg-bar);
}

/* ============================================================
   POINTER PHYSICS — tilt, specular highlight, magnetism
   ============================================================ */
.tilt { transform-style: preserve-3d; will-change: transform; }
.cardspec {
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 3;
  opacity: 0;
  border-radius: inherit;
  background: radial-gradient(circle 200px at var(--mx, 50%) var(--my, 0%),
    rgba(255,255,255,0.22), transparent 62%);
  mix-blend-mode: screen;
  transition: opacity 0.3s var(--ease);
}
:root[data-theme="light"] .cardspec {
  background: radial-gradient(circle 200px at var(--mx, 50%) var(--my, 0%),
    rgba(255,255,255,0.7), transparent 60%);
  mix-blend-mode: soft-light;
}
.tilt:hover .cardspec { opacity: 1; }
.magnetic { will-change: transform; }

/* ============================================================
   SPLASH — Spark intro with star above the K
   ============================================================ */
#splash {
  position: fixed; inset: 0; z-index: 200;
  display: grid; place-items: center;
  background: var(--base);
  overflow: hidden;
}
html.splash-seen #splash { display: none; }
#splash .splash-aurora {
  position: absolute; inset: -10%;
  background:
    radial-gradient(circle at 28% 32%, var(--aurora-purple) 0%, transparent 45%),
    radial-gradient(circle at 74% 64%, var(--aurora-orange) 0%, transparent 42%),
    radial-gradient(circle at 60% 20%, var(--aurora-cyan) 0%, transparent 40%);
  filter: blur(70px);
  opacity: 0.55;
  animation: splash-breathe 3s var(--ease) infinite alternate;
}
@keyframes splash-breathe {
  from { transform: scale(1) translate(0,0); }
  to   { transform: scale(1.12) translate(2%, -1%); }
}
#splash .splash-mark {
  position: relative; z-index: 2;
  display: flex; flex-direction: column; align-items: center; gap: 18px;
  padding: 36px 56px 30px;
  border-radius: var(--r-2xl);
  background: var(--glass-bg);
  backdrop-filter: blur(40px) saturate(180%);
  -webkit-backdrop-filter: blur(40px) saturate(180%);
  border: 1px solid var(--glass-stroke-2);
  box-shadow: inset 0 1px 0 var(--glass-top-hi), 0 40px 90px -20px rgba(0,0,0,0.5);
  animation: splash-pop 0.8s var(--spring) both;
}
@keyframes splash-pop {
  from { transform: scale(0.85); opacity: 0; }
  to   { transform: scale(1); opacity: 1; }
}
#splash .splash-puck {
  width: 64px; height: 64px; border-radius: 18px;
  background:
    radial-gradient(circle at 30% 25%, rgba(255,255,255,0.55), transparent 45%),
    linear-gradient(135deg, #5a6bff 0%, #3d4dc7 40%, #e8472b 100%);
  box-shadow: inset 0 1.5px 0 rgba(255,255,255,0.45), 0 12px 30px rgba(61, 77, 199,0.5);
  animation: splash-puck-in 0.9s var(--spring) 0.1s both;
}
@keyframes splash-puck-in {
  from { transform: scale(0.4) rotate(-18deg); opacity: 0; }
  to   { transform: scale(1) rotate(0); opacity: 1; }
}
/* Miniclip M mark on the splash (above the M360 Spark wordmark). */
#splash .mc-logo {
  width: 88px; height: 88px;
  filter: drop-shadow(0 16px 36px rgba(61,77,199,0.42)) drop-shadow(0 6px 16px rgba(232,71,43,0.32));
  animation: splash-puck-in 0.9s var(--spring) 0.1s both;
}
#splash .mc-logo svg { width: 100%; height: 100%; display: block; }
#splash .splash-word {
  font-size: 58px; font-weight: 680; letter-spacing: -0.03em;
  color: var(--text-1);
  line-height: 1;
}
#splash .splash-word { animation: splash-letter 0.6s var(--spring) 0.4s both; }
@keyframes splash-letter { from { transform: translateY(0.12em); opacity:0; } to { transform: translateY(0); opacity:1; } }
#splash.leaving {
  animation: splash-out 0.7s var(--ease) forwards;
  pointer-events: none;
}
@keyframes splash-out {
  to { opacity: 0; transform: scale(1.04); filter: blur(6px); }
}
#splash .splash-skip {
  position: absolute; bottom: 28px; left: 50%; transform: translateX(-50%);
  z-index: 2;
  font-size: 12px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--text-3);
}

/* Wordmark wrapper: keeps "Spark" as a single plain text run so the
   parent gradient (background-clip:text) fills EVERY letter including the
   K. The star is a sibling absolutely-positioned against this wrapper —
   never wrapping a letter in a positioned box (that paints the glyph
   separately and drops it out of the clipped gradient = the "missing K"). */
.wordmark { position: relative; white-space: nowrap; }
.spark-star {
  display: none; /* only the big splash star reads well; it's an artifact when small */
  position: absolute;
  top: -0.3em; right: -0.34em;
  width: 0.4em; height: 0.4em;
  background: var(--aurora-orange);
  clip-path: polygon(50% 0%, 61% 39%, 100% 50%, 61% 61%, 50% 100%, 39% 61%, 0% 50%, 39% 39%);
  filter: drop-shadow(0 0 6px rgba(255,138,80,0.85));
  animation: star-twinkle 2.6s var(--ease) infinite;
}
#splash .spark-star {
  display: block;
  top: -0.2em; right: -0.4em;
  animation: star-pop 0.6s var(--spring) 0.7s both, star-twinkle 2.6s var(--ease) 1.3s infinite;
}
@keyframes star-pop { from { transform: scale(0) rotate(-90deg); opacity: 0; } to { transform: scale(1) rotate(0); opacity: 1; } }
@keyframes star-twinkle {
  0%, 100% { transform: scale(1) rotate(0); opacity: 0.95; }
  50%      { transform: scale(1.28) rotate(45deg); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  #splash .splash-aurora, #splash .splash-mark, #splash .splash-puck,
  #splash .splash-word, .spark-star { animation: none !important; }
}

/* ============================================================
   ANIMATED SPARK — lives inside the brand puck
   ============================================================ */
.brand-mark { position: relative; overflow: hidden; }
.brand-spark {
  position: absolute; inset: 0;
  pointer-events: none;
  display: grid; place-items: center;
}
.brand-spark .bolt {
  width: 52%; height: 52%;
  color: #fff;
  filter: drop-shadow(0 1px 3px rgba(0,0,0,0.35));
  animation: bolt-pulse 2.8s var(--ease) infinite;
  transform-origin: center;
}
@keyframes bolt-pulse {
  0%, 100% { transform: scale(1) rotate(0); opacity: 0.96; }
  45%      { transform: scale(1.16) rotate(-6deg); opacity: 1; }
  70%      { transform: scale(0.96) rotate(2deg); }
}
.brand-spark .twinkle {
  position: absolute;
  background: #fff;
  border-radius: 50%;
  opacity: 0;
  box-shadow: 0 0 6px rgba(255,255,255,0.9);
  animation: twinkle 2.8s var(--ease) infinite;
}
.brand-spark .twinkle.a { width: 14%; height: 14%; top: 20%; right: 22%; animation-delay: 0.2s; }
.brand-spark .twinkle.b { width: 9%; height: 9%; bottom: 26%; left: 24%; animation-delay: 1.1s; }
@keyframes twinkle {
  0%, 100% { opacity: 0; transform: scale(0.4); }
  30%      { opacity: 0.95; transform: scale(1); }
  55%      { opacity: 0; transform: scale(0.4); }
}
/* sheen sweep across the puck */
.brand-mark::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(115deg, transparent 30%, rgba(255,255,255,0.45) 48%, transparent 62%);
  transform: translateX(-120%);
  animation: puck-sheen 4.5s var(--ease) infinite;
}
@keyframes puck-sheen {
  0%, 62% { transform: translateX(-120%); }
  78%     { transform: translateX(120%); }
  100%    { transform: translateX(120%); }
}
@media (prefers-reduced-motion: reduce) {
  .brand-spark .bolt, .brand-spark .twinkle, .brand-mark::after { animation: none !important; }
  .brand-mark::after { opacity: 0; }
}

/* filtering animation on gallery cards */
/* No `transform` in this transition: the JS 3D tilt sets transform every frame,
   and a transition here would make it chase/lag (the "jittery" tilt). */
.game-card { transition: box-shadow 0.4s var(--ease), opacity 0.35s var(--ease); }
.game-card.filtered-out {
  opacity: 0; transform: scale(0.92);
  pointer-events: none;
}

/* engine filter scroller */
.engine-filters {
  display: flex; gap: 8px; align-items: center;
  overflow-x: auto;
  padding: 4px 2px 10px;
  margin: 0 -2px;
  scrollbar-width: none;
}
.engine-filters::-webkit-scrollbar { display: none; }
.engine-filters .chip { flex-shrink: 0; }
.engine-filters .chip .cnt {
  font-size: 11px; opacity: 0.6; font-weight: 600;
  margin-left: 2px;
}
.engine-filters .chip .swatch-dot {
  width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;
}

/* ============================================================
   MODAL — glass dialog + backdrop
   ============================================================ */
/* ---- Modal-open: freeze the aurora (global) ----
   When ANY modal is open, the animated mix-blend-mode:screen aurora flickers
   through a translucent / blurred scrim — and a backdrop-filter forces it to
   re-rasterise every frame. Pausing the CSS drift keyframes AND fading the layer
   out kills it for good; the JS pointer-parallax is frozen to match in spark.js
   (initAuroraParallax). One rule, every modal — page modals and spark-flows. */
body.modal-open .aurora::before,
body.modal-open .aurora::after,
body.modal-open .aurora .blob { animation-play-state: paused; }
body.modal-open .aurora { opacity: 0; transition: opacity 0.2s var(--ease); }

.modal-backdrop {
  position: fixed; inset: 0; z-index: 120;
  display: grid; place-items: center;
  padding: 24px;
  /* FULLY OPAQUE (no alpha, no backdrop blur): guarantees no animated background can
     flash through, and drops a full-viewport backdrop-filter that re-rasterised the
     drifting aurora every frame. Cheaper AND flicker-proof. */
  background: radial-gradient(ellipse 120% 90% at 50% -10%, #17122a 0%, #08050e 60%);
  opacity: 0;
  transition: opacity 0.3s var(--ease);
}
:root[data-theme="light"] .modal-backdrop { background: radial-gradient(ellipse 120% 90% at 50% -10%, #eceaf5 0%, #d7d4e6 60%); }
.modal-backdrop.in { opacity: 1; }
.modal {
  width: 100%;
  max-width: 540px;
  max-height: calc(100vh - 48px);
  overflow: hidden;
  display: flex; flex-direction: column;
  border-radius: var(--r-2xl);
  background: var(--glass-bg-strong);
  backdrop-filter: blur(42px) saturate(190%);
  -webkit-backdrop-filter: blur(42px) saturate(190%);
  border: 1px solid var(--glass-stroke-2);
  box-shadow:
    inset 0 1px 0 var(--glass-top-hi),
    inset 0 -1px 0 var(--glass-bot-lo),
    0 40px 100px -20px rgba(0,0,0,0.7);
  transform: scale(0.92) translateY(10px);
  opacity: 0;
  transition: transform 0.5s var(--spring), opacity 0.35s var(--ease);
}
.modal.lg { max-width: 600px; }
.modal-backdrop.in .modal { transform: scale(1) translateY(0); opacity: 1; }
.modal-head {
  display: flex; align-items: flex-start; gap: 14px;
  padding: 24px 24px 16px;
}
.modal-head .m-icon {
  width: 44px; height: 44px; border-radius: 13px;
  display: grid; place-items: center; flex-shrink: 0;
  color: white;
  background: linear-gradient(135deg, #4a5ae0, #2bc4e8);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), 0 8px 20px -4px rgba(61, 77, 199,0.5);
}
.modal-head .m-icon.green { background: linear-gradient(135deg, #4be0a8, #34c2e0); box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), 0 8px 20px -4px rgba(75,224,168,0.5); }
.modal-head .m-icon.warn { background: linear-gradient(135deg, #ffb454, #ff7a59); box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), 0 8px 20px -4px rgba(255,138,80,0.5); }
.modal-head .m-icon.danger { background: linear-gradient(135deg, #ff6b6b, #ff8a5c); box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), 0 8px 20px -4px rgba(255,107,107,0.5); }
.modal-head h3 { font-size: 19px; font-weight: 640; }
.modal-head .m-sub { color: var(--text-2); font-size: 13.5px; margin-top: 4px; line-height: 1.5; }
.modal-head .m-x {
  margin-left: auto; width: 32px; height: 32px; border-radius: 50%;
  display: grid; place-items: center; color: var(--text-3);
  background: rgba(255,255,255,0.05); border: 1px solid var(--glass-stroke);
  flex-shrink: 0; transition: background 0.2s, color 0.2s;
}
.modal-head .m-x:hover { background: rgba(255,255,255,0.12); color: var(--text-1); }
:root[data-theme="light"] .modal-head .m-x { background: rgba(20,18,40,0.05); }
.modal-body { padding: 0 24px; overflow-y: auto; }
.modal-foot {
  display: flex; gap: 10px; justify-content: flex-end; align-items: center;
  padding: 18px 24px 22px;
  margin-top: 14px;
  flex-wrap: wrap;
}
.modal-foot .foot-note { margin-right: auto; font-size: 12.5px; color: var(--text-3); }

/* processing / detection visuals inside modal */
.proc-progress {
  height: 8px; border-radius: var(--r-pill);
  background: rgba(255,255,255,0.08); overflow: hidden; margin: 4px 0 18px;
}
:root[data-theme="light"] .proc-progress { background: rgba(20,18,40,0.08); }
.proc-progress .bar {
  height: 100%; width: 0%;
  border-radius: var(--r-pill);
  background: linear-gradient(90deg, #ff6243, #e8472b 42%, #3d4dc7);
  box-shadow: 0 0 14px rgba(255,90,130,0.5);
  transition: width 0.5s var(--ease);
}
.proc-steps { display: flex; flex-direction: column; gap: 2px; }
.proc-step {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 4px;
  font-size: 14px; color: var(--text-3);
  transition: color 0.3s var(--ease);
}
.proc-step .dot {
  width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center; flex-shrink: 0;
  border: 1.5px solid var(--glass-stroke-2);
  color: transparent;
  transition: all 0.3s var(--ease);
}
.proc-step .lbl { flex: 1; }
.proc-step .tail { font-size: 12px; color: var(--text-3); font-family: "SF Mono", ui-monospace, monospace; opacity: 0; transition: opacity 0.3s; }
.proc-step.active { color: var(--text-1); }
.proc-step.active .dot {
  border-color: transparent;
  background: linear-gradient(135deg, #4a5ae0, #2bc4e8);
  box-shadow: 0 0 0 4px rgba(61, 77, 199,0.18);
}
.proc-step.active .dot::after {
  content: ""; width: 9px; height: 9px; border-radius: 50%;
  border: 2px solid rgba(255,255,255,0.5); border-top-color: #fff;
  animation: spin 0.7s linear infinite;
}
.proc-step.done { color: var(--text-2); }
.proc-step.done .dot { border-color: transparent; background: linear-gradient(135deg, #4be0a8, #34c2e0); color: #fff; }
.proc-step.done .tail { opacity: 1; }
.proc-step.done .dot svg { width: 12px; height: 12px; }
@keyframes spin { to { transform: rotate(360deg); } }

/* separated modules list */
.sep-list { display: flex; flex-direction: column; gap: 8px; margin: 4px 0 4px; }
.sep-item {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 14px; border-radius: var(--r-md);
  background: rgba(0,0,0,0.24);
  border: 1px solid var(--glass-stroke);
  opacity: 0; transform: translateX(-8px);
  animation: sep-in 0.45s var(--spring) forwards;
}
:root[data-theme="light"] .sep-item { background: rgba(255,255,255,0.5); }
@keyframes sep-in { to { opacity: 1; transform: none; } }
.sep-item .ic {
  width: 30px; height: 30px; border-radius: 8px; flex-shrink: 0;
  display: grid; place-items: center; color: #fff; font-size: 9px; font-weight: 700;
}
.sep-item .nm { flex: 1; min-width: 0; }
.sep-item .nm strong { font-weight: 580; font-size: 13.5px; color: var(--text-1); display: block; }
.sep-item .nm span { font-size: 12px; color: var(--text-3); }
.sep-item .sz { font-size: 12px; font-family: "SF Mono", ui-monospace, monospace; color: var(--text-2); }

/* detection result chip + signals */
.detect-result {
  display: flex; align-items: center; gap: 14px;
  padding: 16px; border-radius: var(--r-lg);
  background: linear-gradient(135deg, rgba(61, 77, 199,0.12), rgba(255,90,130,0.1));
  border: 1px solid var(--glass-stroke-2);
  margin-bottom: 16px;
}
.detect-result .big-engine {
  width: 52px; height: 52px; border-radius: 14px; flex-shrink: 0;
  display: grid; place-items: center; color: #fff; font-weight: 800; font-size: 13px;
  background: linear-gradient(135deg, #4a5ae0, #2bc4e8);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.3);
}
.detect-result .meta { flex: 1; }
.detect-result .meta .name { font-size: 16px; font-weight: 640; color: var(--text-1); }
.detect-result .meta .ver { font-size: 12.5px; color: var(--text-2); }
.detect-result .conf { text-align: right; }
.detect-result .conf .pct { font-size: 22px; font-weight: 700; letter-spacing: -0.02em; }
.detect-result .conf .pct.high { color: var(--aurora-green); }
.detect-result .conf .pct.mid { color: #ffb454; }
.detect-result .conf .lbl { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-3); }
.signal-list { display: flex; flex-direction: column; gap: 7px; margin-bottom: 8px; }
.signal-list .sig { display: flex; align-items: center; gap: 9px; font-size: 13px; color: var(--text-2); }
.signal-list .sig code { font-family: "SF Mono", ui-monospace, monospace; font-size: 12px; color: var(--text-1); background: rgba(255,255,255,0.07); padding: 1px 6px; border-radius: 5px; }
:root[data-theme="light"] .signal-list .sig code { background: rgba(20,18,40,0.06); }
.signal-list .sig .ok { color: var(--aurora-green); flex-shrink: 0; }

.code-paste {
  width: 100%; min-height: 150px; resize: vertical;
  padding: 14px 16px; border-radius: var(--r-md);
  background: rgba(0,0,0,0.3); border: 1px solid var(--glass-stroke);
  color: var(--text-1); font-family: "SF Mono", ui-monospace, monospace; font-size: 12.5px;
  line-height: 1.5; outline: none;
}
:root[data-theme="light"] .code-paste { background: rgba(255,255,255,0.6); }
.code-paste:focus { border-color: rgba(61, 77, 199,0.5); box-shadow: 0 0 0 4px rgba(61, 77, 199,0.16); }

/* exception callout */
.callout {
  display: flex; gap: 12px; padding: 14px 16px;
  border-radius: var(--r-md); margin-bottom: 8px;
  font-size: 13.5px; line-height: 1.5; color: var(--text-2);
}
.callout.warn { background: rgba(255,138,80,0.1); border: 1px solid rgba(255,138,80,0.26); }
.callout.danger { background: rgba(255,107,107,0.1); border: 1px solid rgba(255,107,107,0.28); }
.callout .ci { flex-shrink: 0; margin-top: 1px; }
.callout.warn .ci { color: #ffb454; }
.callout.danger .ci { color: #ff7a99; }
.callout strong { color: var(--text-1); font-weight: 580; }

/* engine pick grid */
.engine-pick { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin: 4px 0; }
.engine-pick .ep {
  padding: 14px 10px; border-radius: var(--r-md); text-align: center; cursor: pointer;
  background: rgba(255,255,255,0.04); border: 1px solid var(--glass-stroke);
  transition: background 0.2s, border-color 0.2s, transform 0.25s var(--spring);
}
:root[data-theme="light"] .engine-pick .ep { background: rgba(20,18,40,0.04); }
.engine-pick .ep:hover { transform: translateY(-2px); background: rgba(255,255,255,0.09); }
.engine-pick .ep.sel { border-color: rgba(61, 77, 199,0.6); background: rgba(61, 77, 199,0.14); }
.engine-pick .ep .dotc { width: 12px; height: 12px; border-radius: 50%; margin: 0 auto 8px; }
.engine-pick .ep .en { font-size: 12.5px; font-weight: 560; color: var(--text-1); }

/* ============================================================
   TOASTS
   ============================================================ */
.toast-stack {
  position: fixed; left: 50%; top: 92px; bottom: auto; transform: translateX(-50%);
  z-index: 150; display: flex; flex-direction: column; gap: 10px;
  align-items: center; pointer-events: none;
}
@media (max-width: 900px) { .toast-stack { top: 78px; } }
.toast {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 18px 12px 14px; border-radius: var(--r-pill);
  background: var(--glass-bg-strong);
  backdrop-filter: blur(32px) saturate(180%);
  -webkit-backdrop-filter: blur(32px) saturate(180%);
  border: 1px solid var(--glass-stroke-2);
  box-shadow: inset 0 1px 0 var(--glass-top-hi), 0 18px 44px -10px rgba(0,0,0,0.5);
  font-size: 14px; color: var(--text-1); font-weight: 500;
  pointer-events: auto;
  transform: translateY(-16px) scale(0.96); opacity: 0;
  transition: transform 0.5s var(--spring), opacity 0.3s var(--ease);
  max-width: 92vw;
}
/* Toast can carry a small thumbnail (live game-update notifications). */
.toast .tt-thumb-img { width: 30px; height: 30px; border-radius: 8px; object-fit: cover; flex-shrink: 0; border: 1px solid var(--glass-stroke); }
.toast .ti.up { background: linear-gradient(135deg, #34e0ff, #4be0a8); }
.toast .ti.msg { background: linear-gradient(135deg, #3d4dc7, #34e0ff); }
.toast.in { transform: none; opacity: 1; }
.toast .ti {
  width: 26px; height: 26px; border-radius: 50%; flex-shrink: 0;
  display: grid; place-items: center; color: #fff;
}
.toast .ti.ok { background: linear-gradient(135deg, #4be0a8, #34c2e0); }
.toast .ti.info { background: linear-gradient(135deg, #4a5ae0, #2bc4e8); }
.toast .ti.warn { background: linear-gradient(135deg, #ffb454, #ff7a59); }

/* ============================================================
   SCENARIO SWITCHER (prototype QA affordance, upload page)
   ============================================================ */
.scenario-bar {
  margin-top: 18px;
  padding: 12px 14px;
  border-radius: var(--r-lg);
  background: rgba(61, 77, 199,0.07);
  border: 1px dashed rgba(61, 77, 199,0.32);
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
:root[data-theme="light"] .scenario-bar { background: rgba(61, 77, 199,0.08); }
.scenario-bar .sb-label {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 11.5px; font-weight: 640; letter-spacing: 0.06em; text-transform: uppercase;
  color: #b9a6ff;
}
.scenario-bar .sb-label svg { width: 13px; height: 13px; }
:root[data-theme="light"] .scenario-bar .sb-label { color: #6b48d6; }
.scenario-bar .sb-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.scenario-bar .sc {
  height: 28px; padding: 0 11px; border-radius: var(--r-pill);
  font-size: 12px; font-weight: 540; color: var(--text-2);
  background: rgba(255,255,255,0.05); border: 1px solid var(--glass-stroke);
  cursor: pointer; transition: background 0.2s, color 0.2s, transform 0.2s var(--spring);
}
:root[data-theme="light"] .scenario-bar .sc { background: rgba(255,255,255,0.5); }
.scenario-bar .sc:hover { color: var(--text-1); transform: translateY(-1px); }
.scenario-bar .sc:active { transform: translateY(0); }

/* ============================================================
   Disabled / not-yet-built controls (demo cleanliness)
   ============================================================ */
.nav a.nav-off {
  opacity: 0.32;
  pointer-events: none;
  cursor: default;
}
.is-disabled {
  opacity: 0.4 !important;
  pointer-events: none !important;
  cursor: not-allowed !important;
  filter: saturate(0.4);
}

/* ============================================================
   AI Description (gallery card + game page)
   ============================================================ */
.ai-chip {
  display: inline-block;
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 7px; border-radius: var(--r-pill);
  color: #fff; vertical-align: middle;
  background: linear-gradient(135deg, #3d4dc7, #34e0ff);
  box-shadow: 0 2px 8px -2px rgba(61, 77, 199,0.6);
}
.game-card .ai-desc {
  font-size: 12px; line-height: 1.45; color: var(--text-2);
  margin: 6px 0 2px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.game-card .ai-desc .ai-chip { font-size: 8.5px; padding: 1px 6px; margin-right: 4px; }
.ai-desc-line {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin-top: 14px; max-width: 60ch;
  font-size: 14.5px; line-height: 1.5; color: var(--text-2);
}
.ai-desc-line .ai-chip { flex-shrink: 0; align-self: center; }

/* ============================================================
   Game play-frame is always dark → keep its inner text light in
   light mode too (otherwise theme tokens make it invisible).
   ============================================================ */
:root[data-theme="light"] .hero-frame .hint,
:root[data-theme="light"] .hero-frame .hint kbd,
:root[data-theme="light"] .hero-frame .frame-corner { color: rgba(255,255,255,0.92); }
:root[data-theme="light"] .hero-frame .hint { background: rgba(15,15,25,0.55); border-color: rgba(255,255,255,0.12); }
:root[data-theme="light"] .hero-frame .frame-corner { background: rgba(15,15,25,0.55); border-color: rgba(255,255,255,0.14); }

/* inline edit pencil (owner/admin) — used next to the author credit, the AI
   description line, and the About heading. */
.edit-pen {
  background: transparent; border: 0; cursor: pointer;
  color: var(--text-3); font-size: 12.5px; line-height: 1;
  padding: 2px 6px; border-radius: 6px; margin-left: 4px;
  vertical-align: middle; transition: color 0.15s, background 0.15s, transform 0.15s var(--spring);
}
.edit-pen:hover { color: var(--text-1); background: rgba(255,255,255,0.08); transform: translateY(-1px); }
:root[data-theme="light"] .edit-pen:hover { background: rgba(20,18,40,0.06); }
.about-card h3 .edit-pen { opacity: 0.55; }
.about-card h3:hover .edit-pen { opacity: 1; }
.ai-desc-line .edit-pen { opacity: 0.55; }
.ai-desc-line:hover .edit-pen { opacity: 1; }

/* ============================================================
   MOTION — modern, GPU-cheap (transform/opacity only)
   ============================================================ */

/* Cross-page transition is defined ONCE at the top of this file (the smooth
   opacity dissolve). Re-declaring it here previously overrode it with a
   blur+scale variant that caused the navigation "fluctuation" — removed. */

/* Brighter liquid lens — the pointer-follow specular on cards reads clearly now. */
.cardspec {
  background: radial-gradient(circle 240px at var(--mx, 50%) var(--my, 0%),
    rgba(255,255,255,0.42), rgba(255,255,255,0.06) 48%, transparent 66%);
}

/* Hover sheen sweep — a light streak glides across the lit CTAs (liquid glass).
   NOTE: never set position on .fab (it must stay position:fixed). */
.btn-primary, .btn-success { isolation: isolate; }
.btn-primary::after, .btn-success::after { pointer-events: none; }
.btn-primary:hover::after, .btn-success:hover::after {
  background:
    radial-gradient(120% 80% at 18% -20%, rgba(255,255,255,0.4), transparent 50%),
    linear-gradient(100deg, transparent 38%, rgba(255,255,255,0.45) 50%, transparent 62%);
  background-size: 100% 100%, 240% 100%;
  background-position: 0 0, 130% 0;
  animation: cta-sweep 0.85s var(--ease);
}
@keyframes cta-sweep {
  0%   { background-position: 0 0, 130% 0; }
  100% { background-position: 0 0, -60% 0; }
}

/* Entrance: cards rise + fade in, gently staggered. Runs on insert/paint. */
@keyframes card-rise {
  from { opacity: 0; transform: translateY(18px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}
/* NOTE: card entrance is handled per-card by the IntersectionObserver reveal in
   spark.js (.gc-pre → .gc-in, cleared on animationend). A global
   `animation: card-rise both` here used to hold `transform:none` via its fill,
   which OVERRODE both the :hover lift and the JS 3D tilt — removed. */

/* Scroll/load reveal utility (JS adds .is-in when in view). */
.reveal { opacity: 0; transform: translateY(20px); transition: opacity 0.55s var(--ease), transform 0.55s var(--ease); }
.reveal.is-in { opacity: 1; transform: none; }

/* On-load lift for the top bar + first hero block. */
@keyframes bar-drop { from { opacity: 0; transform: translateY(-12px); } to { opacity: 1; transform: none; } }
.topbar-wrap { animation: bar-drop 0.5s var(--ease) both; }

@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
  .game-card, .topbar-wrap { animation: none !important; }
  .reveal { opacity: 1 !important; transform: none !important; transition: none !important; }
  .btn-primary:hover::after, .btn-success:hover::after { animation: none !important; }
}

/* ============================================================
   LIQUID GLASS — iOS-style refinements
   Tactile press "squish", a brighter continuous lens edge, and concentric
   rounding so controls read as discrete floating glass capsules.
   ============================================================ */

/* Tactile press feedback (the control momentarily compresses, like iOS). */
.btn:active, .chip:active, .iconbtn:active,
.reaction:active, .share-btn:active, .seg:active,
.btn-sm:active, .btn-xs:active { transform: scale(0.95); }
.fab:active, .play-btn-big:active { transform: scale(0.96) !important; }
.game-card:active { transform: translateY(-2px) scale(0.992); }
@media (prefers-reduced-motion: reduce) {
  .btn:active, .chip:active, .iconbtn:active, .fab:active, .game-card:active { transform: none !important; }
}

/* Brighter, more continuous "lit lens" edge on the floating surfaces. */
.glass::before, .glass-strong::before, .game-card::before, .hero-frame::before, .topbar::before { opacity: 0.95; }
.glass-strong::before { opacity: 1; }

/* ============================================================================
   ★ LIQUID GLASS 2.0 — design refresh (ported verbatim from design:/style.css)
   Authoritative override block: redefines tokens + recipes so every surface
   re-derives. Markup/data-action/window.Spark untouched. ============================ */

/* use the reference page-out/leave choreography instead of the MPA crossfade */
@view-transition { navigation: none; }

:root {
  --aurora-purple: #7c5cff;
  --aurora-orange: #ff7a59;
  --aurora-cyan:   #34e0ff;
  --aurora-pink:   #ff5c8d;
  --aurora-green:  #3ddc97;
  --base:          #05040b;
  --base-2:        #110e1c;
  --text-1: rgba(255, 255, 255, 0.96);
  --text-2: rgba(255, 255, 255, 0.68);
  --text-3: rgba(255, 255, 255, 0.44);
  /* adaptive tint */
  --glass-rgb: 16, 14, 26;
  --tint: 0.14;
  --tint-panel: 0.40;
  --tint-dense: 0.70;
  --glass-bg:        rgba(var(--glass-rgb), calc(var(--tint) * 0.6 + 0.09));
  --glass-bg-strong: rgba(var(--glass-rgb), calc(var(--tint-dense) * 0.6 + 0.20));
  --glass-bg-bar:    rgba(var(--glass-rgb), calc(var(--tint) * 0.6 + 0.11));
  --glass-stroke:    rgba(255, 255, 255, 0.10);
  --glass-stroke-2:  rgba(255, 255, 255, 0.15);
  --glass-top-hi:    rgba(255, 255, 255, 0.55);
  --glass-bot-lo:    rgba(0, 0, 0, 0.32);
  --glass-edge:      rgba(0, 0, 0, 0.42);
  --spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease:   cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* ---- aurora: calm, low-opacity, near-black base ---- */
.aurora { background: var(--base); }
/* more present aurora (was reading near jet-black): brighter blooms + a lighter
   centre vignette so the colour shows through behind the glass. */
.aurora::before, .aurora::after, .aurora .blob { filter: blur(48px); opacity: 0.5; }
.aurora::before { width: 760px; height: 760px; left: -150px; top: -170px; background: radial-gradient(circle, var(--aurora-purple) 0%, transparent 66%); }
.aurora::after { width: 860px; height: 860px; right: -190px; top: -120px; background: radial-gradient(circle, var(--aurora-orange) 0%, transparent 62%); }
.aurora .blob.c { width: 720px; height: 720px; left: 16%; bottom: -250px; background: radial-gradient(circle, var(--aurora-cyan) 0%, transparent 64%); opacity: 0.4; }
.aurora .blob.p { width: 560px; height: 560px; right: 8%; bottom: -150px; background: radial-gradient(circle, var(--aurora-pink) 0%, transparent 64%); opacity: 0.36; }
.aurora-vignette { background:
  radial-gradient(ellipse 86% 64% at 50% 42%, transparent 0%, rgba(10,6,18,0.12) 58%, rgba(10,6,18,0.6) 100%),
  linear-gradient(180deg, rgba(10,6,18,0.4) 0%, transparent 22%, transparent 80%, rgba(10,6,18,0.62) 100%); }
.aurora-grain { opacity: 0.05; mix-blend-mode: overlay; }

/* ---- glass recipe ---- */
.glass {
  background: linear-gradient(180deg, rgba(255,255,255,0.12), transparent 42%), var(--glass-bg);
  backdrop-filter: blur(34px) saturate(225%) brightness(1.06) contrast(1.03);
  -webkit-backdrop-filter: blur(34px) saturate(225%) brightness(1.06) contrast(1.03);
  border: 1px solid var(--glass-stroke); border-radius: var(--r-xl);
  box-shadow: 0 0 0 0.5px var(--glass-edge), inset 0 1px 0.5px var(--glass-top-hi),
    inset 0 8px 22px -14px rgba(255,255,255,0.22), inset 0 -1px 1px var(--glass-bot-lo),
    0 24px 60px -14px rgba(0,0,0,0.55), 0 8px 22px -8px rgba(0,0,0,0.34);
  position: relative;
}
.glass-strong {
  background: linear-gradient(180deg, rgba(255,255,255,0.12), transparent 40%), var(--glass-bg-strong);
  backdrop-filter: blur(42px) saturate(210%) brightness(1.05) contrast(1.02);
  -webkit-backdrop-filter: blur(42px) saturate(210%) brightness(1.05) contrast(1.02);
  border: 1px solid var(--glass-stroke-2); border-radius: var(--r-xl);
  box-shadow: 0 0 0 0.5px var(--glass-edge), inset 0 1px 0.5px var(--glass-top-hi),
    inset 0 8px 22px -14px rgba(255,255,255,0.24), inset 0 -1px 1px var(--glass-bot-lo),
    0 32px 80px -16px rgba(0,0,0,0.65), 0 10px 30px -8px rgba(0,0,0,0.4);
  position: relative;
}
.glass::before, .glass-strong::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 1px;
  background: linear-gradient(135deg, var(--glass-top-hi) 0%, transparent 34%, transparent 62%, var(--glass-edge) 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none; opacity: 0.9;
}
.glass::after, .glass-strong::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: linear-gradient(180deg, rgba(255,255,255,0.10) 0%, transparent 28%); opacity: 0.7; mix-blend-mode: screen;
}

/* ---- topbar ---- */
.topbar {
  background: var(--glass-bg-bar);
  backdrop-filter: blur(32px) saturate(180%); -webkit-backdrop-filter: blur(32px) saturate(180%);
  border: 1px solid var(--glass-stroke);
  box-shadow: inset 0 1px 0 var(--glass-top-hi), inset 0 -1px 0 var(--glass-bot-lo), 0 18px 50px -10px rgba(0,0,0,0.55);
}

/* ---- CTAs: amber primary + animated edge-light FAB (+green) ---- */
@property --fab-a { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
.btn-primary {
  color: #fff; background: linear-gradient(135deg, #ffc24d 0%, #ff8a3d 52%, #ff6a3a 100%);
  border: 1px solid rgba(255,255,255,0.22);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.4), inset 0 -1px 0 rgba(0,0,0,0.2),
    0 10px 24px -6px rgba(255,140,60,0.55), 0 4px 10px -2px rgba(255,100,50,0.4);
}
.btn-primary:hover { transform: translateY(-2px); box-shadow: inset 0 1px 0 rgba(255,255,255,0.45),
    inset 0 -1px 0 rgba(0,0,0,0.2), 0 14px 32px -6px rgba(255,140,60,0.65), 0 6px 14px -2px rgba(255,100,50,0.5); }
.btn-success { color: #fff; background: linear-gradient(135deg, #4be0a8 0%, #34c2e0 100%);
  border: 1px solid rgba(255,255,255,0.2); box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), 0 10px 24px -6px rgba(75,224,168,0.45); }
.fab {
  overflow: hidden;
  background: linear-gradient(135deg, #ffc24d 0%, #ff8a3d 52%, #ff6a3a 100%);
  border: 1px solid rgba(255,255,255,0.22);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.4), inset 0 -2px 6px rgba(0,0,0,0.2),
    0 18px 40px -8px rgba(255,140,60,0.55), 0 8px 20px -4px rgba(255,100,50,0.45);
  transition: transform 0.3s var(--spring), box-shadow 0.3s;
}
.fab.green { background: linear-gradient(135deg, #5be584 0%, #2ec96a 52%, #1faf57 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.4), inset 0 -2px 6px rgba(0,0,0,0.2),
    0 18px 40px -8px rgba(46,201,106,0.55), 0 8px 20px -4px rgba(31,175,87,0.45); }
.fab:hover { transform: translateY(-3px) scale(1.02); }
.fab > * { position: relative; z-index: 2; }
.fab::before {
  content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit; padding: 1.6px;
  background: conic-gradient(from var(--fab-a), transparent 0deg, rgba(255,255,255,0.95) 34deg, rgba(255,255,255,0.25) 72deg, transparent 100deg, transparent 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none; opacity: 0.6; mix-blend-mode: screen;
  animation: fab-orbit 3.6s linear infinite;
}
.fab:hover::before { opacity: 1; animation-duration: 1.8s; }
@keyframes fab-orbit { to { --fab-a: 360deg; } }
.fab::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(115deg, transparent 36%, rgba(255,255,255,0.4) 50%, transparent 62%);
  transform: translateX(-130%); animation: fab-sheen 5s var(--ease) infinite;
}
@keyframes fab-sheen { 0%, 62% { transform: translateX(-130%); } 80%, 100% { transform: translateX(130%); } }
@media (prefers-reduced-motion: reduce) { .fab::before, .fab::after { animation: none !important; } }

/* ---- light mode tiers ---- */
:root[data-theme="light"] {
  --aurora-purple: #7b5cff; --aurora-orange: #ff7a59; --aurora-cyan: #2bc7ef; --aurora-pink: #ff5c8d; --aurora-green: #2bbf85;
  /* Cooler, slightly deeper base so frosted-white glass panels visibly SEPARATE
     from the page (was #eceefb near-white → white-on-white, no glass feel). */
  --base: #e5e8f2; --base-2: #eef1f9;
  --text-1: rgba(18,16,34,0.94); --text-2: rgba(28,24,48,0.62); --text-3: rgba(38,34,60,0.44);
  --glass-rgb: 255, 255, 255; --tint: 0.18; --tint-panel: 0.50; --tint-dense: 0.84;
  /* Genuinely TRANSLUCENT frosted glass (not flat opaque white) so the blurred
     aurora tints through and it reads as liquid glass. Backdrop-blur stays on. */
  --glass-bg:        rgba(var(--glass-rgb), 0.52);
  --glass-bg-strong: rgba(var(--glass-rgb), 0.74);
  --glass-bg-bar:    rgba(var(--glass-rgb), 0.80);
  --glass-stroke: rgba(20,18,40,0.12); --glass-stroke-2: rgba(20,18,40,0.18);
  --glass-top-hi: rgba(255,255,255,0.95); --glass-bot-lo: rgba(20,18,40,0.06); --glass-edge: rgba(40,36,80,0.16);
}
:root[data-theme="light"] .glass, :root[data-theme="light"] .game-card, :root[data-theme="light"] .index-card {
  box-shadow: inset 0 1px 0 var(--glass-top-hi), inset 0 -1px 0 var(--glass-bot-lo),
    0 22px 56px -16px rgba(40,36,80,0.28), 0 8px 22px -10px rgba(40,36,80,0.18); }
:root[data-theme="light"] .glass-strong { box-shadow: inset 0 1px 0 var(--glass-top-hi), 0 30px 72px -18px rgba(40,36,80,0.32), 0 10px 28px -10px rgba(40,36,80,0.2); }
:root[data-theme="light"] .topbar { box-shadow: inset 0 1px 0 var(--glass-top-hi), 0 16px 44px -14px rgba(40,36,80,0.26); }
:root[data-theme="light"] .aurora::before { opacity: 0.55; } :root[data-theme="light"] .aurora::after { opacity: 0.55; }
:root[data-theme="light"] .aurora .blob.c { opacity: 0.46; } :root[data-theme="light"] .aurora .blob.p { opacity: 0.44; }
:root[data-theme="light"] .aurora-grain { opacity: 0.04; mix-blend-mode: multiply; }
:root[data-theme="light"] .aurora-vignette { background:
  radial-gradient(ellipse 80% 60% at 50% 45%, transparent 0%, rgba(236,238,251,0.45) 55%, rgba(236,238,251,0.85) 100%),
  linear-gradient(180deg, rgba(236,238,251,0.6) 0%, transparent 18%, transparent 78%, rgba(236,238,251,0.85) 100%); }

/* ---- page / filter / card motion ---- */
@keyframes card-in { from { opacity: 0; transform: translateY(16px) scale(0.95); } to { opacity: 1; transform: none; } }
@keyframes page-in { from { opacity: 0; transform: translateY(10px) scale(0.995); } to { opacity: 1; transform: none; } }
@keyframes page-out { to { opacity: 0; transform: scale(0.99) translateY(-8px); filter: blur(3px); } }
body.leaving { animation: page-out 0.3s var(--ease) forwards; pointer-events: none; }
@keyframes orb-spin { to { transform: rotate(360deg); } }
/* breathe = GLOW ONLY (no transform). It used to animate transform:scale, which
   overrode orb-spin's rotate (two animations on one property → last wins), so the
   orb only pulsed and never rotated. Glow-only lets orb-spin actually rotate. */
@keyframes orb-breathe { 0%, 100% { box-shadow: 0 0 8px 1px rgba(124,92,255,0.42), inset 0 0 0 1px rgba(255,255,255,0.16); } 50% { box-shadow: 0 0 18px 4px rgba(52,224,255,0.6), inset 0 0 0 1px rgba(255,255,255,0.28); } }
@keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(61,220,151,0.55); } 70% { box-shadow: 0 0 0 10px rgba(61,220,151,0); } 100% { box-shadow: 0 0 0 0 rgba(61,220,151,0); } }
/* Siri-orb status dot (gallery "N prototypes" swatch) */
.summary-strip .pill-stat .swatch {
  position: relative; overflow: visible; border-radius: 50%;
  background: conic-gradient(from 0deg, #34e0ff, #7c5cff, #ff5c8d, #ffb454, #34e0ff) !important;
  animation: orb-spin 3.6s linear infinite, orb-breathe 4s ease-in-out infinite;
}
.summary-strip .pill-stat .swatch::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle at 34% 28%, rgba(255,255,255,0.9), transparent 42%), radial-gradient(circle at 64% 88%, rgba(255,255,255,0.28), transparent 46%);
  mix-blend-mode: screen;
}
@media (prefers-reduced-motion: reduce) { body.leaving, .summary-strip .pill-stat .swatch { animation: none; } }

/* ---- thumbnail → QR flip ---- */
.thumb { perspective: 1100px; }
.thumb .flip-inner { position: relative; width: 100%; height: 100%; transform-style: preserve-3d; transition: transform 0.7s var(--spring); }
.game-card.flipped .thumb .flip-inner { transform: rotateY(180deg); }
.thumb .flip-front, .thumb .flip-back { position: absolute; inset: 0; backface-visibility: hidden; -webkit-backface-visibility: hidden; }
.thumb .flip-back { transform: rotateY(180deg); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  background: radial-gradient(circle at 50% 26%, #1b1533 0%, transparent 60%), linear-gradient(160deg, #120e20, #07050d); }
.qr-wrap { width: 56%; max-width: 144px; }
.qr-wrap svg { width: 100%; height: auto; display: block; border-radius: 14px; box-shadow: 0 10px 28px -6px rgba(0,0,0,0.6), inset 0 0 0 1px rgba(255,255,255,0.06); }
.game-card.flipped .qr-wrap svg { animation: qr-pop 0.55s var(--spring) 0.12s; }
@keyframes qr-pop { from { opacity: 0; transform: scale(0.8); } to { opacity: 1; transform: none; } }
.qr-cap { display: inline-flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 600; color: var(--text-2); }
.qr-cap .pulse { width: 7px; height: 7px; border-radius: 50%; background: var(--aurora-green); box-shadow: 0 0 0 0 rgba(61,220,151,0.6); animation: pulse 2.4s ease-out infinite; }
.qr-toggle { position: absolute; bottom: 12px; left: 12px; z-index: 6; width: 34px; height: 34px; border-radius: 11px; display: grid; place-items: center; color: #fff;
  background: rgba(8,5,14,0.74); border: 1px solid rgba(255,255,255,0.16); /* solid fill, NO blur (43-card re-raster cost — see play-icon note in gallery.html) */
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.2), 0 6px 16px rgba(0,0,0,0.4); cursor: pointer; transition: transform 0.25s var(--spring), background 0.2s; }
.qr-toggle:hover { background: rgba(8,5,14,0.72); transform: translateY(-2px) scale(1.06); }
.qr-toggle:active { transform: scale(0.94); }
.qr-toggle .ic-qr, .qr-toggle .ic-close { display: grid; place-items: center; }
.qr-toggle .ic-close { display: none; }
.game-card.flipped .qr-toggle .ic-qr { display: none; }
.game-card.flipped .qr-toggle .ic-close { display: grid; }
.game-card.flipped .qr-toggle { background: rgba(255,255,255,0.14); }
@media (prefers-reduced-motion: reduce) { .thumb .flip-inner { transition: none; } .qr-wrap svg, .game-card.flipped .qr-wrap svg { animation: none; } }

/* ---- themed, dark-grounded thumbnails ---- */
.thumb.th1 { background: radial-gradient(115% 92% at 28% 24%, rgba(255,122,89,.20) 0%, transparent 58%), radial-gradient(95% 80% at 82% 84%, rgba(124,92,255,.17) 0%, transparent 56%), linear-gradient(155deg, #150f28, #09070f); }
.thumb.th2 { background: radial-gradient(115% 92% at 72% 24%, rgba(52,224,255,.20) 0%, transparent 58%), radial-gradient(95% 80% at 18% 84%, rgba(124,92,255,.16) 0%, transparent 56%), linear-gradient(155deg, #0b1728, #050810); }
.thumb.th3 { background: radial-gradient(115% 92% at 50% 26%, rgba(255,92,141,.20) 0%, transparent 58%), radial-gradient(95% 80% at 50% 96%, rgba(255,122,89,.16) 0%, transparent 60%), linear-gradient(155deg, #1f0d13, #0c0407); }
.thumb.th4 { background: radial-gradient(115% 92% at 22% 26%, rgba(61,220,151,.19) 0%, transparent 58%), radial-gradient(95% 80% at 90% 84%, rgba(52,224,255,.15) 0%, transparent 56%), linear-gradient(155deg, #081b14, #03100a); }
.thumb.th5 { background: radial-gradient(115% 92% at 80% 26%, rgba(255,122,89,.20) 0%, transparent 58%), radial-gradient(95% 80% at 20% 90%, rgba(255,92,141,.16) 0%, transparent 56%), linear-gradient(155deg, #1f0d13, #0c0407); }
.thumb.th6 { background: radial-gradient(115% 92% at 30% 80%, rgba(199,121,255,.20) 0%, transparent 58%), radial-gradient(95% 80% at 82% 20%, rgba(52,224,255,.15) 0%, transparent 56%), linear-gradient(155deg, #150c28, #070414); }
.thumb.th7 { background: radial-gradient(115% 92% at 50% 60%, rgba(255,175,92,.20) 0%, transparent 58%), radial-gradient(95% 80% at 82% 20%, rgba(255,92,141,.15) 0%, transparent 56%), linear-gradient(155deg, #1e1206, #0e0703); }
.thumb.th8 { background: radial-gradient(115% 92% at 28% 26%, rgba(52,224,255,.19) 0%, transparent 58%), radial-gradient(95% 80% at 72% 84%, rgba(61,220,151,.15) 0%, transparent 56%), linear-gradient(155deg, #05191f, #020c12); }
.thumb.th9 { background: radial-gradient(120% 95% at 50% 46%, rgba(255,122,89,.19) 0%, transparent 60%), linear-gradient(155deg, #1f0d13, #0c0407); }

/* ============================================================================
   ★ LIQUID GLASS 2.0 — round 2 fixes (cards edge-lit, aurora present, flip) ===
   ============================================================================ */

/* ----------------------------------------------------------------------------
   AURORA (round 3) — the blobs were stuck in the corners with NO screen-blend,
   and the vignette darkened exactly those edges → "jet black". Fix: paint the
   aurora directly onto .aurora as always-visible radial washes (warm top-left →
   cool top-right → teal floor, just like the reference), keep the blobs only as
   subtle screen-blend drift, gut the vignette, and remove the grain texture.
   ------------------------------------------------------------------------- */
:root { --base: #0b0816; }

/* ★ THE root cause of every "jet black" report: BOTH html AND body had an opaque
   background. The fixed .aurora sits at z-index:-2, so in the paint order the
   body's own opaque background painted right over it — the aurora was never
   visible. Keep the base only on <html> (the canvas fallback) and make <body>
   transparent so the aurora behind the content actually shows. */
html { background: var(--base); }
body { background: transparent !important; }

.aurora {
  background:
    radial-gradient(135% 95% at 16% -12%, rgba(124,92,255,0.40), transparent 56%),
    radial-gradient(130% 90% at 88% -8%,  rgba(255,122,89,0.30), transparent 56%),
    radial-gradient(120% 95% at 50% 118%, rgba(52,224,255,0.20), transparent 60%),
    radial-gradient(ellipse 120% 80% at 50% -6%, #18112f 0%, transparent 55%),
    var(--base) !important;
}
.aurora::before, .aurora::after, .aurora .blob {
  /* blur(96px) on four full-viewport layers was the single biggest paint cost
     across every page (the "heavy/slow" feel — the aurora is the global bg). The
     blobs are radial gradients already fading to transparent, so a 48px blur looks
     all but identical at a fraction of the rasterisation cost (blur ∝ radius²). */
  mix-blend-mode: screen; filter: blur(48px) !important;
}
.aurora::before { opacity: 0.5 !important; }
.aurora::after  { opacity: 0.42 !important; }
.aurora .blob.c { opacity: 0.32 !important; }
.aurora .blob.p { opacity: 0.30 !important; }

/* Vignette: only a whisper at the very bottom for text legibility — never the
   top, where the aurora lives. */
.aurora-vignette {
  background:
    radial-gradient(ellipse 110% 80% at 50% 38%, transparent 52%, rgba(8,5,16,0.26) 100%),
    linear-gradient(180deg, transparent 62%, rgba(8,5,16,0.46) 100%) !important;
}
.aurora-grain { display: none !important; }   /* user: remove the texture */

:root[data-theme="light"] .aurora {
  background:
    radial-gradient(135% 95% at 16% -12%, rgba(139,107,255,0.26), transparent 58%),
    radial-gradient(130% 90% at 88% -8%,  rgba(255,138,90,0.18),  transparent 58%),
    radial-gradient(120% 95% at 50% 118%, rgba(43,199,239,0.16),  transparent 60%),
    radial-gradient(ellipse 120% 80% at 50% -6%, #ffffff 0%, transparent 55%),
    var(--base) !important;
}
:root[data-theme="light"] .aurora-vignette {
  background:
    radial-gradient(ellipse 110% 80% at 50% 38%, transparent 56%, rgba(225,228,242,0.4) 100%),
    linear-gradient(180deg, transparent 64%, rgba(225,228,242,0.55) 100%) !important;
}

/* ----------------------------------------------------------------------------
   EDGE-LIT GLASS CARDS (round 3) — NO backdrop-filter. A per-card blur
   re-samples the animated aurora every scroll frame → the "weird squares" /
   sticky-clunky scroll the user reported. The glass look comes entirely from
   the bevel: bright top edge + dark rim + wrap-light ::before + a readable
   semi-opaque fill. Cheap to paint, smooth to scroll.
   ------------------------------------------------------------------------- */
.game-card {
  background:
    linear-gradient(180deg, rgba(255,255,255,0.10), rgba(255,255,255,0) 38%),
    rgba(20,17,34,0.64) !important;
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
  border: 1px solid var(--glass-stroke);
  box-shadow:
    0 0 0 0.5px var(--glass-edge),
    inset 0 1px 0.5px var(--glass-top-hi),
    inset 0 10px 26px -16px rgba(255,255,255,0.20),
    inset 0 -1px 1px var(--glass-bot-lo),
    0 24px 60px -16px rgba(0,0,0,0.5),
    0 8px 22px -10px rgba(0,0,0,0.32);
}
.game-card::before {  /* refractive wrap-light edge (bright TL → dark BR) */
  content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 1px; z-index: 1;
  background: linear-gradient(135deg, var(--glass-top-hi) 0%, transparent 34%, transparent 62%, var(--glass-edge) 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none; opacity: 0.9;
}
:root[data-theme="light"] .game-card {
  background:
    linear-gradient(180deg, rgba(255,255,255,0.9), rgba(255,255,255,0.6) 38%),
    rgba(255,255,255,0.72) !important;
  box-shadow: inset 0 1px 0 var(--glass-top-hi), inset 0 -1px 0 var(--glass-bot-lo),
    0 22px 56px -16px rgba(40,36,80,0.26), 0 8px 22px -10px rgba(40,36,80,0.16);
}

/* The QR flip must sit ABOVE the hover gameplay-preview media (which the card
   adds on top of the thumb), or clicking the glyph flips behind it = "nothing". */
.thumb .flip-inner { z-index: 3; }
.game-card.flipped .thumb .flip-back { z-index: 4; }
.game-card.flipped .thumb > :not(.flip-inner):not(.qr-toggle) { opacity: 0; pointer-events: none; }

/* Make the orb's spin unmistakable (bigger gradient contrast + a clear sweep). */
.summary-strip .pill-stat .swatch { width: 24px !important; height: 24px !important; }

/* Scroll-aware topbar: gains tint as content moves behind it (set by spark.js). */
.topbar { transition: background 0.3s var(--ease), box-shadow 0.3s var(--ease); }
.topbar.scrolled { background: rgba(var(--glass-rgb), 0.84) !important; backdrop-filter: blur(34px) saturate(180%) !important; -webkit-backdrop-filter: blur(34px) saturate(180%) !important; }
:root[data-theme="light"] .topbar.scrolled { background: rgba(var(--glass-rgb), 0.92) !important; }

/* ============================================================================
   ★ LIQUID GLASS 2.0 — round 4 fixes
   ============================================================================ */

/* FAB: kill the conic-gradient "orbit" entirely. When the ring-mask fails on a
   GPU the conic renders as a rotating bright WEDGE — the "strange line cutting
   through the button" the user saw. Keep only the smooth linear sheen sweep. */
.fab-edge { display: none !important; }
.fab::before { display: none !important; }

/* ── Random "blinking" cure: contain the aurora's mix-blend ───────────────────
   The aurora's 4 drifting layers use `mix-blend-mode: screen` (+ blur). On some
   GPUs an animated screen-blend re-rasterises the layers it composites against
   every frame, so fixed/elevated elements sitting over it (the green "Drop a
   build" FAB, the topbar) FLICKER as the aurora drifts — the "constant random
   blinking". `isolation: isolate` gives the aurora its own blend group so the
   screen-blend resolves WITHIN the aurora and never touches anything above it.
   Visually identical over the near-black base (verified); the flicker source is
   gone. The FAB is also promoted to its own stable compositing layer so a
   backdrop repaint can never re-raster it. (modal-open already freezes the
   aurora; this fixes the IDLE case.) */
.aurora { isolation: isolate; }
.fab { isolation: isolate; -webkit-backface-visibility: hidden; backface-visibility: hidden; }

/* Orb: the user has asked 3+ times for it to spin. It was silenced by the
   reduce-motion guard. Decorative ambient spin is an explicit request, so it
   now rotates regardless of the OS Reduce-Motion setting. */
.summary-strip .pill-stat .swatch {
  animation: orb-spin 4.2s linear infinite, orb-breathe 4s ease-in-out infinite !important;
  background: conic-gradient(from 0deg, #34e0ff, #7c5cff, #ff5c8d, #ffb454, #34e0ff) !important;
  will-change: transform;
}

/* Smooth card scroll-reveal: pre-hidden cards (set by spark.js) ease in with a
   GPU-only fade + lift + scale as they enter the viewport — no mass animation,
   no scroll jank. */
/* Scroll reveal: pre-hide with opacity ONLY (no transform that could linger and
   fight the tilt). IO swaps gc-pre→gc-in which runs a one-shot keyframe; spark.js
   removes the class on animationend so nothing holds a transform afterwards. */
.game-card.gc-pre, .index-card.gc-pre, .app-card.gc-pre { opacity: 0; }
.game-card.gc-in, .index-card.gc-in, .app-card.gc-in { animation: card-rise 0.5s var(--spring) both; }
@media (prefers-reduced-motion: reduce) {
  .game-card.gc-pre, .index-card.gc-pre, .app-card.gc-pre { opacity: 1; }
  .game-card.gc-in, .index-card.gc-in, .app-card.gc-in { animation: none; }
}

/* Hover glow + lift for Android-build & index cards (the gallery card already
   has its own :hover glow). The JS tilt adds the 3D rotate on top. */
.app-card, .index-card { transition: box-shadow 0.4s var(--ease), opacity 0.35s var(--ease); }
.app-card:hover, .index-card:hover {
  box-shadow:
    inset 0 1px 0 var(--glass-top-hi),
    0 0 0 1px rgba(90,107,255,0.26),
    0 28px 64px -14px rgba(61,77,199,0.4),
    0 10px 26px -6px rgba(232,71,43,0.2),
    0 8px 20px -4px rgba(0,0,0,0.4);
}

/* Mobile: the horizontally-scrolling filter pills had no "more →" affordance.
   A soft right-edge mask hints there's more to swipe. */
@media (max-width: 760px) {
  .engine-filters {
    -webkit-mask-image: linear-gradient(90deg, #000 86%, transparent 100%);
    mask-image: linear-gradient(90deg, #000 86%, transparent 100%);
  }
}

/* ============================================================================
   ★ LIQUID GLASS 2.0 — round 5: button feedback + qr-toggle clarity
   ============================================================================ */

/* The QR-flip toggle was 50% translucent, so on cards whose motif accent is
   green/teal it bled through and looked like a random green button. More opaque
   = a consistent dark "scan QR" chip on every card. */
.qr-toggle { background: rgba(10, 8, 18, 0.78) !important; }
:root[data-theme="light"] .qr-toggle { background: rgba(255,255,255,0.82) !important; color: var(--text-1); }

/* Universal press feedback — no button should feel "dead" on click. */
button:not(:disabled):active,
.btn:active, .btn-primary:active, .chip:active, .iconbtn:active,
.dl-btn:active, .share-btn:active, .scan-btn:active, .vote-btn:active,
.app-fav:active, .fav-btn:active, .qr-toggle:active, .apk-pen:active,
.reaction:active, .vote-cta:active, [data-action]:active {
  transform: scale(0.94);
}
/* a quick "tap" flash on icon-style buttons so the press registers visually */
.share-btn:active, .scan-btn:active, .iconbtn:active, .qr-toggle:active { filter: brightness(1.25); }

/* ============================================================================
   ★ LIQUID GLASS 2.0 — round 6: mobile nav (hamburger) + filter polish
   ============================================================================ */
.nav-toggle { display: none; }   /* desktop: hidden (full nav shows) */
@media (max-width: 1000px) {
  .nav-toggle {
    display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
    width: 40px; height: 40px; flex: 0 0 auto; border-radius: 11px; cursor: pointer;
    background: var(--glass-bg); border: 1px solid var(--glass-stroke); box-shadow: inset 0 1px 0 var(--glass-top-hi);
    margin-left: 6px;
  }
  .nav-toggle span { display: block; width: 18px; height: 2px; border-radius: 2px; background: var(--text-1); transition: transform 0.25s var(--ease), opacity 0.2s; }
  .topbar.nav-open .nav-toggle span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
  .topbar.nav-open .nav-toggle span:nth-child(2) { opacity: 0; }
  .topbar.nav-open .nav-toggle span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }
  /* the nav drops down as a glass panel when toggled open */
  .topbar.nav-open .nav {
    display: flex; flex-direction: column; gap: 2px;
    position: absolute; top: calc(100% + 10px); right: 0; min-width: 220px; max-width: calc(100vw - 24px);
    padding: 8px; border-radius: 16px; z-index: 60;
    background: rgba(var(--glass-rgb), 0.92); -webkit-backdrop-filter: blur(28px) saturate(180%); backdrop-filter: blur(28px) saturate(180%);
    border: 1px solid var(--glass-stroke); box-shadow: inset 0 1px 0 var(--glass-top-hi), 0 24px 60px -12px rgba(0,0,0,0.6);
    animation: nav-drop 0.22s var(--ease) both;
  }
  .topbar.nav-open .nav a { padding: 12px 14px; border-radius: 11px; font-size: 14.5px; }
}
@keyframes nav-drop { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .topbar.nav-open .nav { animation: none; } }

/* ============================================================
   LIGHT-MODE READABILITY + DROPDOWN CONSISTENCY (lg65)
   Status chips/badges/labels across the app hardcoded light pastel
   colours (mint/amber/pink/lavender/cyan) with NO light override, so
   they rendered light-on-white. These dark-on-light variants restore
   contrast. `:root[data-theme="light"] .x` outranks bare `.x` in any
   page's inline <style>, so these win regardless of file order.
   ============================================================ */
:root[data-theme="light"] {
  /* GREEN / mint → readable dark green */
  --lt-green: #0a7a50; --lt-green-bg: rgba(10,122,80,0.10); --lt-green-bd: rgba(10,122,80,0.26);
  /* AMBER / gold → dark amber */
  --lt-amber: #8a5200; --lt-amber-bg: rgba(138,82,0,0.10); --lt-amber-bd: rgba(138,82,0,0.26);
  /* RED / pink → dark red */
  --lt-red: #b0172e; --lt-red-bg: rgba(176,23,46,0.10); --lt-red-bd: rgba(176,23,46,0.28);
  /* BLUE / cyan → dark blue */
  --lt-blue: #0069a0; --lt-blue-bg: rgba(0,105,160,0.10); --lt-blue-bd: rgba(0,105,160,0.26);
  /* PURPLE / lavender → dark violet */
  --lt-purple: #4a28b8; --lt-purple-bg: rgba(74,40,184,0.10); --lt-purple-bd: rgba(74,40,184,0.26);
}
/* admin — people status + role badges */
:root[data-theme="light"] .badge.active  { color: var(--lt-green);  background: var(--lt-green-bg);  border-color: var(--lt-green-bd); }
:root[data-theme="light"] .badge.blocked { color: var(--lt-red);    background: var(--lt-red-bg);    border-color: var(--lt-red-bd); }
:root[data-theme="light"] .badge.admin   { color: var(--lt-purple); background: var(--lt-purple-bg); border-color: var(--lt-purple-bd); }
/* admin — activity feed kinds */
:root[data-theme="light"] .act .kind.signin { color: var(--lt-green); background: var(--lt-green-bg); }
:root[data-theme="light"] .act .kind.upload,
:root[data-theme="light"] .act .kind.deploy { color: var(--lt-blue);  background: var(--lt-blue-bg); }
:root[data-theme="light"] .act .kind.block  { color: var(--lt-red);   background: var(--lt-red-bg); }
/* admin — watchdog severity + diff */
:root[data-theme="light"] .wd-sev.fail { color: var(--lt-red);   background: var(--lt-red-bg);   border-color: var(--lt-red-bd); }
:root[data-theme="light"] .wd-sev.warn { color: var(--lt-amber); background: var(--lt-amber-bg); border-color: var(--lt-amber-bd); }
:root[data-theme="light"] .wd-diff-new { color: var(--lt-green); }
:root[data-theme="light"] .btn-xs.primary { background: linear-gradient(135deg, #d45a00, #b83d00); color: #fff; }
/* analytics — greenlight status chips, banners, deltas, leaderboard, stuck tag */
:root[data-theme="light"] .gl-chip.st-green, :root[data-theme="light"] .gl-banner.green, :root[data-theme="light"] .lb-green { color: var(--lt-green); background: var(--lt-green-bg); border-color: var(--lt-green-bd); }
:root[data-theme="light"] .gl-chip.st-amber, :root[data-theme="light"] .gl-banner.amber { color: var(--lt-amber); background: var(--lt-amber-bg); border-color: var(--lt-amber-bd); }
:root[data-theme="light"] .gl-chip.st-blue { color: var(--lt-blue); background: var(--lt-blue-bg); border-color: var(--lt-blue-bd); }
:root[data-theme="light"] .an-stat .delta.up, :root[data-theme="light"] .lb-rise { color: var(--lt-green); }
:root[data-theme="light"] .stuck-tag { color: var(--lt-red); background: var(--lt-red-bg); border-color: var(--lt-red-bd); }
/* analytics — dark tooltips must flip to a light card in light mode */
:root[data-theme="light"] .an-tip { background: rgba(255,255,255,0.98); color: var(--text-1); border: 1px solid rgba(20,18,40,0.14); box-shadow: 0 8px 22px -6px rgba(40,36,80,0.2); }
/* gallery — card badges + update-feed kinds */
:root[data-theme="light"] .game-card .badge.greenlit { color: var(--lt-green); background: var(--lt-green-bg); border-color: var(--lt-green-bd); }
:root[data-theme="light"] .game-card .heat { color: var(--lt-amber); background: var(--lt-amber-bg); border-color: var(--lt-amber-bd); }
:root[data-theme="light"] .upd-kind.new_game { color: var(--lt-green); background: var(--lt-green-bg); }
:root[data-theme="light"] .upd-kind.new_version { color: var(--lt-blue); background: var(--lt-blue-bg); }
:root[data-theme="light"] .upd-kind.new_apk, :root[data-theme="light"] .upd-kind.apk_version { color: var(--lt-amber); background: var(--lt-amber-bg); }
/* deploy — mint eyebrow/links */
:root[data-theme="light"] .hero .eyebrow, :root[data-theme="light"] .copy-row .copy-btn, :root[data-theme="light"] .copied-hint { color: var(--lt-green); }
/* apk — status + extraction badges */
:root[data-theme="light"] .apk-status.ok { color: var(--lt-green); }
:root[data-theme="light"] .apk-status.warn { color: var(--lt-amber); }
:root[data-theme="light"] .extr-badge.auto { color: var(--lt-green); background: var(--lt-green-bg); }
:root[data-theme="light"] .extr-badge.gen { color: var(--lt-purple); background: var(--lt-purple-bg); }
:root[data-theme="light"] .extr-badge.manual { color: var(--lt-amber); background: var(--lt-amber-bg); }

/* ---- DROPDOWN CONSISTENCY ----
   (1) Option popups: theme bg+text for ALL native selects (var flips per theme,
       so dark = dark popup/light text, light = light popup/dark text). Fixes the
       "dark popup, invisible text in light mode" on #unit / #fb-version. */
.input option, .select option, .an-sort option, select option { background: var(--base-2); color: var(--text-1); }
/* (2) Active/selected row in the custom dropdowns used cyan that vanished on white. */
:root[data-theme="light"] .pm-row.on, :root[data-theme="light"] .sort-opt.on, :root[data-theme="light"] .sort-opt-check { color: #186b8a; }
/* (3) Custom-dropdown trigger hover border was a white overlay → invisible on light. */
:root[data-theme="light"] .sort-pick:hover, :root[data-theme="light"] .profile-pick:hover { border-color: rgba(20,18,40,0.22); }
/* (4) Standardise the secondary native selects (#unit, #fb-version, #bulk-owner)
       to the analytics .an-sort look: no OS arrow, a themed glass fill, and a
       custom chevron. var(--glass-bg-strong) + var(--text-1) flip per theme. */
/* ---- Notifications bell + pane (spark.js initNotifications) ---- */
.iconbtn .dot.count {
  position: absolute; top: -3px; right: -3px; min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: 99px; background: linear-gradient(135deg, #ff6243, #e8472b); color: #fff;
  font-size: 10px; font-weight: 800; line-height: 16px; text-align: center;
  box-shadow: 0 2px 6px -1px rgba(232,71,43,0.6); border: 1.5px solid var(--base, #0a0612);
}
.notif-pane {
  position: fixed !important; z-index: 1000; width: 360px; max-width: calc(100vw - 16px);
  padding: 8px; border-radius: 14px; display: flex; flex-direction: column;
  animation: um-in 0.16s var(--ease) both;
}
.notif-head { display: flex; align-items: center; justify-content: space-between; padding: 6px 8px 8px; }
.notif-head-t { font-size: 13px; font-weight: 680; color: var(--text-1); }
.notif-mark { border: 0; background: transparent; color: var(--aurora-cyan); font-size: 12px; font-weight: 600; cursor: pointer; padding: 2px 4px; }
.notif-mark:hover { text-decoration: underline; }
.notif-list { display: flex; flex-direction: column; gap: 4px; max-height: 60vh; overflow-y: auto; scrollbar-width: thin; }
.notif-empty { padding: 26px 14px; text-align: center; color: var(--text-3); font-size: 12.5px; line-height: 1.5; }
.notif-item { display: flex; gap: 10px; padding: 10px; border-radius: 10px; text-decoration: none; color: inherit; background: transparent; transition: background .15s; position: relative; }
.notif-item:hover { background: rgba(255,255,255,0.06); }
:root[data-theme="light"] .notif-item:hover { background: rgba(20,18,40,0.05); }
.notif-item.unread { background: rgba(120,150,255,0.10); }
.notif-item.unread::before { content: ""; position: absolute; left: 3px; top: 50%; transform: translateY(-50%); width: 6px; height: 6px; border-radius: 50%; background: var(--aurora-cyan); }
.notif-item.pri { box-shadow: inset 2px 0 0 var(--aurora-orange); }
.notif-av { flex: 0 0 auto; width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; font-size: 12px; font-weight: 800; color: #fff; background: linear-gradient(135deg, #7c5cff, #34c2e0); }
.notif-av.pri { background: linear-gradient(135deg, #ff9a3d, #ff6243); font-size: 15px; }
.notif-main { min-width: 0; flex: 1; }
.notif-t { font-size: 13px; font-weight: 620; color: var(--text-1); }
.notif-b { font-size: 12px; color: var(--text-2); margin-top: 1px; line-height: 1.4; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.notif-time { font-size: 11px; color: var(--text-3); margin-top: 3px; }

/* Shared custom-dropdown component (SparkUI.enhanceSelect + gallery/analytics sort).
   One source of truth so every dropdown's OPEN popup is the same themed glass panel
   on every page, both themes. */
.sort-pick { display: inline-flex; align-items: center; gap: 8px; height: 38px; padding: 0 12px; border-radius: 11px; background: var(--glass-bg); border: 1px solid var(--glass-stroke); color: var(--text-1); font-size: 13px; font-weight: 600; cursor: pointer; transition: border-color 0.18s, background 0.18s; }
.sort-pick:hover { border-color: var(--glass-stroke-2); background: rgba(255,255,255,0.06); }
.sort-pick-chev { color: var(--text-3); transition: transform 0.2s var(--ease); transform-box: fill-box; transform-origin: center; }
.sort-pick.open .sort-pick-chev { transform: rotate(180deg); }
.sort-menu { position: fixed !important; z-index: 1000; min-width: 190px; padding: 6px; border-radius: 12px; display: flex; flex-direction: column; animation: um-in 0.16s var(--ease) both; }
@keyframes um-in { from { opacity: 0; transform: translateY(-5px); } }
.sort-opt { display: flex; align-items: center; justify-content: space-between; gap: 12px; width: 100%; text-align: left; height: 34px; padding: 0 10px; border: 0; border-radius: 8px; background: transparent; color: var(--text-1); font-size: 13px; font-weight: 540; cursor: pointer; }
.sort-opt:hover { background: rgba(255,255,255,0.08); }
.sort-opt.on { color: var(--aurora-cyan); font-weight: 660; }
.sort-opt-check { color: var(--aurora-cyan); flex: 0 0 auto; }
:root[data-theme="light"] .sort-opt:hover { background: rgba(20,18,40,0.06); }

select.input, select.select {
  -webkit-appearance: none !important; appearance: none !important;
  background-color: var(--glass-bg-strong) !important;
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='12'%20height='12'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%239b94b5'%20stroke-width='2.5'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpolyline%20points='6%209%2012%2015%2018%209'/%3E%3C/svg%3E") !important;
  background-repeat: no-repeat !important;
  background-position: right 12px center !important;
  padding-right: 34px; color: var(--text-1);
}
