/* ============================================================
   gv-neon.css — arcade skin for the Glyphverse.

   Everything is scoped under `body.gv-neon`, so the skin is opt-in per page
   and can be pulled by removing one class. It restyles surfaces, adds the lit
   backdrop, and provides the shared HUD pieces (combo badge, score readout,
   sound toggle) that the games mount into.

   THEME CONTRACT
   The site ships a dark default and a light variant keyed off
   :root[data-theme="light"], with --bg/--card/--text/--muted/--line as the
   source of truth. This skin *derives* from those tokens rather than
   replacing them: every colour below resolves through a --nx-* token that is
   redeclared in the light block, so the player's light/dark choice still
   decides what the page looks like. Nothing here hard-codes a dark surface,
   and nothing paints a colour onto a generic element (p/div/span), which is
   what broke both the theme toggle and the satisfied-clue numbers before.

   Selectors are written `:root body.gv-neon ...`. The leading :root is not
   decoration: the site's light rules are `:root[data-theme="light"] .seg.on`
   and friends, which outrank a bare `body.gv-neon .seg.on`. Without the
   prefix the skin would win `color` and lose `background` on the same
   element — white-on-white — which is how the earlier revision ended up
   needing !important on nearly every line. One extra :root replaces all of
   them and keeps the light-theme token block (which carries both) on top.
   ============================================================ */

:root body.gv-neon{
  /* Accents — vivid on black. */
  --nx-cyan:      #3ee8ff;
  --nx-blue:      #5aa8ff;
  --nx-violet:    #b07cff;
  --nx-pink:      #ff6ad5;
  --nx-gold:      #ffc850;
  --nx-lime:      #7dff9b;
  --nx-red:       #ff5a72;

  /* Surfaces + ink follow the site's own theme tokens. */
  --nx-void:      #05070f;
  --nx-ink:       var(--text, #eaf3ff);
  --nx-dim:       var(--muted, rgba(234,243,255,.62));
  --nx-line:      rgba(110,190,255,.20);
  --nx-glass:     rgba(16,26,48,.66);
  --nx-glass-hi:  rgba(28,44,78,.72);

  /* Text drawn on top of an accent fill. */
  --nx-on-accent: #04121a;
  /* The lighter stop of a filled gradient. On dark it lifts toward white; on
     light it must go the other way, or the top of the fill loses contrast
     with the white text sitting on it. */
  --nx-fill-tint: #ffffff;
  /* Display text that carries a glow (score, banners). */
  --nx-hero:      #ffffff;
  --nx-link:      #8fe9ff;
  /* Glow strength multiplier — dimmed in light mode, where bloom on white
     reads as blur rather than light. */
  --nx-glow:      1;
  --nx-blur:      9px;

  /* Chain badge fill. Over a dark page a translucent wash of the accent is
     enough; over white it disappears, so the light build gets an opaque chip. */
  --nx-badge-bg:  color-mix(in srgb, var(--nx-accent) 13%, transparent);

  --nx-aurora-1:  rgba(62,232,255,.16);
  --nx-aurora-2:  rgba(176,124,255,.15);
  --nx-aurora-3:  rgba(255,106,213,.10);
  --nx-grid:      rgba(110,190,255,.05);
  --nx-drop:      rgba(0,0,0,.55);

  --nx-accent:    var(--nx-cyan);

  background: var(--nx-void);
  color: var(--nx-ink);
}

/* ------------------------------------------------------------
   Light mode — same arcade, daylight cabinet.

   Accents are darkened until they carry text contrast on white (the lime
   below is 5.1:1 against #fff, so white numerals sit on it legibly), glass
   becomes frosted white, and glow gives way to coloured drop shadow.
   ------------------------------------------------------------ */
:root[data-theme="light"] body.gv-neon{
  --nx-cyan:      #0a7f99;
  --nx-blue:      #2a63d8;
  --nx-violet:    #7233c9;
  --nx-pink:      #c32488;
  --nx-gold:      #9a6b00;
  --nx-lime:      #0e7f45;
  --nx-red:       #c62033;

  --nx-void:      #eef2f9;
  --nx-ink:       var(--text, #0b0f14);
  --nx-dim:       var(--muted, #435565);
  --nx-line:      rgba(18,38,72,.16);
  --nx-glass:     rgba(255,255,255,.78);
  --nx-glass-hi:  rgba(255,255,255,.94);

  --nx-on-accent: #ffffff;
  --nx-fill-tint: #0b0f14;
  /* Display text is the accent itself, pushed dark enough to clear 4.5:1
     against the frosted panels it sits on. */
  --nx-hero:      color-mix(in srgb, var(--nx-accent) 82%, #000);
  --nx-link:      #0a6a86;
  --nx-glow:      .34;
  --nx-blur:      4px;

  --nx-badge-bg:  color-mix(in srgb, var(--nx-accent) 17%, #fff);

  --nx-aurora-1:  rgba(62,180,255,.20);
  --nx-aurora-2:  rgba(150,110,255,.16);
  --nx-aurora-3:  rgba(255,120,200,.12);
  --nx-grid:      rgba(30,70,130,.06);
  --nx-drop:      rgba(24,42,74,.14);
}

/* Lit backdrop: two slow aurora blooms over a faint grid. Fixed and behind
   everything, so it costs one composited layer and never reflows. */
:root body.gv-neon::before{
  content:"";
  position: fixed; inset: -20vmax;
  z-index: -2;
  background:
    radial-gradient(38vmax 30vmax at 18% 12%, var(--nx-aurora-1), transparent 60%),
    radial-gradient(42vmax 34vmax at 84% 8%,  var(--nx-aurora-2), transparent 62%),
    radial-gradient(46vmax 38vmax at 50% 108%, var(--nx-aurora-3), transparent 60%),
    var(--nx-void);
  animation: nxDrift 26s ease-in-out infinite alternate;
}
:root body.gv-neon::after{
  content:"";
  position: fixed; inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    linear-gradient(to right, var(--nx-grid) 1px, transparent 1px),
    linear-gradient(to bottom, var(--nx-grid) 1px, transparent 1px);
  background-size: 44px 44px;
  mask-image: radial-gradient(72vmax 60vmax at 50% 28%, #000 35%, transparent 78%);
}
@keyframes nxDrift{
  0%  { transform: translate3d(0,0,0) scale(1); }
  100%{ transform: translate3d(-3%, 2%, 0) scale(1.06); }
}

/* Panels become lit glass. */
:root body.gv-neon .card,
:root body.gv-neon .bgCard,
:root body.gv-neon .nxPanel{
  background: linear-gradient(180deg, var(--nx-glass-hi), var(--nx-glass));
  border: 1px solid var(--nx-line);
  border-radius: 18px;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--nx-accent) calc(8% * var(--nx-glow)), transparent) inset,
    0 18px 50px var(--nx-drop),
    0 0 44px color-mix(in srgb, var(--nx-accent) calc(8% * var(--nx-glow)), transparent);
  backdrop-filter: blur(var(--nx-blur));
}

:root body.gv-neon .muted,
:root body.gv-neon .sub{ color: var(--nx-dim); }

/* ---------- HUD ---------- */
:root body.gv-neon .nxHud{
  display:flex; align-items:center; justify-content:space-between;
  gap: 10px; flex-wrap: wrap;
}

:root body.gv-neon .nxScore{
  font: 900 clamp(30px, 9vw, 46px)/1 'Outfit', system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
  letter-spacing: .01em;
  color: var(--nx-hero);
  text-shadow:
    0 0 14px color-mix(in srgb, var(--nx-accent) calc(100% * var(--nx-glow)), transparent),
    0 0 40px color-mix(in srgb, var(--nx-accent) calc(100% * var(--nx-glow)), transparent);
  transition: text-shadow .25s ease, color .25s ease;
}
:root body.gv-neon .nxScoreLabel{
  font-size: 11px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--nx-dim);
}

/* Combo badge — appears on a chain, escalates colour, pops on each step. */
:root body.gv-neon .nxCombo{
  display:inline-flex; align-items:baseline; gap:8px;
  padding: 7px 14px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--nx-accent) 55%, transparent);
  background: var(--nx-badge-bg);
  color: var(--nx-ink);
  font: 800 14px/1 'Outfit', system-ui, sans-serif;
  box-shadow: 0 0 22px color-mix(in srgb, var(--nx-accent) calc(42% * var(--nx-glow)), transparent);
  opacity: 0; transform: translateY(6px) scale(.9);
  transition: opacity .2s ease, transform .28s cubic-bezier(.34,1.56,.64,1);
  pointer-events: none;
}
:root body.gv-neon .nxCombo.on{ opacity:1; transform: translateY(0) scale(1); }
:root body.gv-neon .nxComboX{
  font-size: 20px; font-weight: 900;
  color: var(--nx-hero);
  text-shadow: 0 0 12px color-mix(in srgb, var(--nx-accent) calc(100% * var(--nx-glow)), transparent);
}

/* Progress / rank meter — a filled light bar with a travelling sheen. */
:root body.gv-neon .nxMeter{
  position: relative;
  height: 12px; border-radius: 999px;
  background: color-mix(in srgb, var(--nx-ink) 8%, transparent);
  border: 1px solid var(--nx-line);
  overflow: hidden;
}
:root body.gv-neon .nxMeterFill{
  position:absolute; inset:0 auto 0 0;
  width: 0%;
  border-radius: 999px;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--nx-accent) 78%, var(--nx-fill-tint)),
    var(--nx-accent));
  box-shadow:
    0 0 18px color-mix(in srgb, var(--nx-accent) calc(100% * var(--nx-glow)), transparent),
    0 0 40px color-mix(in srgb, var(--nx-accent) calc(55% * var(--nx-glow)), transparent);
  transition: width .6s cubic-bezier(.2,.8,.25,1);
}
:root body.gv-neon .nxMeterFill::after{
  content:"";
  position:absolute; inset:0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.55), transparent);
  transform: translateX(-100%);
  animation: nxSheen 2.6s ease-in-out infinite;
}
@keyframes nxSheen{ 0%{transform:translateX(-100%)} 55%,100%{transform:translateX(320%)} }

/* Rank-up banner sweep. */
:root body.gv-neon .nxBanner{
  position: fixed; left: 0; right: 0; top: 34%;
  z-index: 10058;
  pointer-events: none;
  text-align: center;
  font: 900 clamp(26px, 8vw, 44px)/1.1 'Outfit', system-ui, sans-serif;
  color: var(--nx-hero);
  text-shadow:
    0 0 18px color-mix(in srgb, var(--nx-accent) calc(100% * var(--nx-glow)), transparent),
    0 0 60px color-mix(in srgb, var(--nx-accent) calc(100% * var(--nx-glow)), transparent);
  opacity: 0;
}
:root body.gv-neon .nxBanner.on{ animation: nxBannerIn 1.5s cubic-bezier(.2,.8,.25,1) forwards; }
:root body.gv-neon .nxBanner::before{
  content:""; position:absolute; left:0; right:0; top:50%; height:2px;
  transform: translateY(-50%) scaleX(0);
  background: linear-gradient(90deg, transparent, var(--nx-accent), transparent);
  box-shadow: 0 0 24px color-mix(in srgb, var(--nx-accent) calc(100% * var(--nx-glow)), transparent);
  animation: nxBannerLine 1.5s cubic-bezier(.2,.8,.25,1) forwards;
}
@keyframes nxBannerIn{
  0%{opacity:0; transform: scale(.72) }
  18%{opacity:1; transform: scale(1.06) }
  34%{transform: scale(1) }
  78%{opacity:1}
  100%{opacity:0; transform: scale(1.02) }
}
@keyframes nxBannerLine{
  0%{transform:translateY(-50%) scaleX(0); opacity:0}
  22%{transform:translateY(-50%) scaleX(1); opacity:1}
  100%{transform:translateY(-50%) scaleX(1); opacity:0}
}

/* Sound toggle. */
:root body.gv-neon .nxSound{
  width: 40px; height: 40px;
  display:inline-flex; align-items:center; justify-content:center;
  border-radius: 12px;
  border: 1px solid var(--nx-line);
  background: color-mix(in srgb, var(--nx-ink) 5%, transparent);
  color: var(--nx-ink);
  font-size: 17px; line-height: 1; cursor: pointer;
  transition: box-shadow .2s ease, border-color .2s ease, transform .12s ease;
}
:root body.gv-neon .nxSound:hover{ border-color: color-mix(in srgb, var(--nx-accent) 60%, transparent); }
:root body.gv-neon .nxSound:active{ transform: scale(.93); }
:root body.gv-neon .nxSound[aria-pressed="true"]{
  border-color: var(--nx-accent);
  box-shadow: 0 0 18px color-mix(in srgb, var(--nx-accent) calc(55% * var(--nx-glow)), transparent);
}

/* Shake root wrapper — gv-fx translates this for camera shake. */
:root body.gv-neon .nxShakeRoot{ will-change: transform; }

@media (prefers-reduced-motion: reduce){
  :root body.gv-neon::before{ animation: none; }
  :root body.gv-neon .nxMeterFill::after{ animation: none; }
  :root body.gv-neon .nxBanner.on,
  :root body.gv-neon .nxBanner::before{ animation-duration: .01ms; }
}

/* ============================================================
   Shared site chrome.

   Deliberately narrow. Earlier revisions painted --nx-ink onto
   body/p/li/span/div/summary/label to stop black-on-black once the skin had
   forced a dark page under the light theme. That blanket did two kinds of
   damage: it made the theme toggle a no-op, and because it matched generic
   children it also overrode component text — the nonogram's satisfied-clue
   numbers are <div>s inside the green pill, so they came out white on
   near-white and became unreadable. Now that the skin follows the theme,
   inherited colour is already correct and only genuine surfaces are restyled.
   ============================================================ */
:root body.gv-neon .brandName{
  text-shadow: 0 0 18px color-mix(in srgb, var(--nx-accent) calc(35% * var(--nx-glow)), transparent);
}

:root body.gv-neon a{ color: var(--nx-link); }
:root body.gv-neon a:hover{ color: color-mix(in srgb, var(--nx-link) 70%, var(--nx-ink)); }

/* Segmented controls / chips / ghost buttons used across the site. */
:root body.gv-neon .seg,
:root body.gv-neon .chip,
:root body.gv-neon .pillbtn,
:root body.gv-neon .ghost{
  color: var(--nx-ink);
  background: color-mix(in srgb, var(--nx-ink) 5%, transparent);
  border: 1px solid var(--nx-line);
  transition: transform .12s ease, box-shadow .2s ease, border-color .2s ease, background .2s ease;
}
:root body.gv-neon .seg:hover,
:root body.gv-neon .chip:hover,
:root body.gv-neon .pillbtn:hover,
:root body.gv-neon .ghost:hover{
  border-color: color-mix(in srgb, var(--nx-accent) 60%, transparent);
  box-shadow: 0 0 18px color-mix(in srgb, var(--nx-accent) calc(26% * var(--nx-glow)), transparent);
}
:root body.gv-neon .seg:active,
:root body.gv-neon .chip:active,
:root body.gv-neon .pillbtn:active{ transform: scale(.95); }

/* Selected segment is the lit one. */
:root body.gv-neon .seg.on{
  background: linear-gradient(180deg, var(--nx-accent), color-mix(in srgb, var(--nx-accent) 62%, #000));
  border-color: transparent;
  color: var(--nx-on-accent);
  font-weight: 900;
  box-shadow: 0 0 24px color-mix(in srgb, var(--nx-accent) calc(45% * var(--nx-glow)), transparent);
}

:root body.gv-neon .ngStatsPill,
:root body.gv-neon .statsPill{
  background: color-mix(in srgb, var(--nx-ink) 5%, transparent);
  border: 1px solid var(--nx-line);
  color: var(--nx-dim);
}

:root body.gv-neon .learnStep,
:root body.gv-neon .faqA{ color: var(--nx-dim); }
