/* ============================================================
   NeuralRun — Global Navigation (shared component)
   Paired with nav.js. Context set via <body data-nav-context>:
     "hub" → dashboard / profile / settings (expanded sidebar on desktop)
     "app" → games / tools (collapsed icon rail + peek on desktop)
   Relies on CSS custom properties already defined in each page's :root
   (--accent-creation, --text-main, --text-dim, etc.)
   ============================================================ */

/* ── THE NAV OWNS ITS TYPEFACE ──
   The nav used to render `font-family: var(--nrnav-font)`,
   which sounds safe but isn't: --font-ui is defined by each PAGE's stylesheet,
   so the fallback never fired and the "global" nav rendered in whatever the app
   happened to declare. Measured: Roboto Mono on misfire/marathon/glowgrid,
   Fira Code on discover/infinite-room/live-poll, and — because
   smart-lists.css:33 sets --font-ui to a system sans stack — SANS-SERIF on
   Smart Lists. Three typefaces for one component.

   Own it here instead. Roboto Mono leads because it carries a true 500 and is
   loaded on the most pages; Fira Code is the second stop (it's the only mono
   loaded on Smart Lists), then system mono. The stack can vary slightly by page
   depending on what's linked, but it can no longer fall out of monospace.

   Weight note: Roboto Mono ships 400/500/700, Fira Code ships 400/600/700.
   600 is the ONLY value that resolves to a real bold-ish face in both (Fira
   600, Roboto rounds to 700). Asking for 500 silently degrades to 400 on Fira
   Code pages, so nav chrome uses 600 and never 500. */
:root {
  --nrnav-font: 'Roboto Mono', 'Fira Code', ui-monospace, SFMono-Regular, Menlo, monospace;
  /* Idle nav-link ink. Own token rather than --text-dim because the nav needs a
     contrast floor it controls: #a8a8ba is 8.45:1 on the dark drawer (AAA),
     where the inherited --text-dim #858595 was only 5.45:1 (AA). Overridden for
     light theme further down — #a8a8ba on the #f7f8fc drawer is 2.20:1, a hard
     fail, so this token MUST be re-set anywhere the drawer surface flips. */
  --nrnav-link: #a8a8ba;
}

/* Restore the HTML `hidden` attribute semantic globally. Class-level rules
   like `.btn { display: inline-flex }` beat the user-agent default
   `[hidden] { display: none }`, leaving `<button hidden>` visible.
   This one rule heals every `[hidden]` site across the suite. */
[hidden] {
  display: none !important;
}

/* Global default scrollbars. Firefox uses scrollbar-color; Chromium/Safari use
   the webkit pseudo-elements below. Scoped to html so nested app scrollers can
   inherit unless they intentionally override. */
html {
  --nr-scrollbar-track: #08080c;
  --nr-scrollbar-thumb: rgba(122, 92, 255, 0.58);
  --nr-scrollbar-thumb-hover: rgba(0, 243, 255, 0.72);
  scrollbar-color: var(--nr-scrollbar-thumb) var(--nr-scrollbar-track);
  scrollbar-width: thin;
}
html[data-theme="light"] {
  --nr-scrollbar-track: #eef1f7;
  --nr-scrollbar-thumb: rgba(122, 92, 255, 0.46);
  --nr-scrollbar-thumb-hover: rgba(0, 144, 168, 0.64);
}
::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
::-webkit-scrollbar-track {
  background: var(--nr-scrollbar-track);
}
::-webkit-scrollbar-thumb {
  background: var(--nr-scrollbar-thumb);
  border: 2px solid var(--nr-scrollbar-track);
  border-radius: 999px;
}
::-webkit-scrollbar-thumb:hover {
  background: var(--nr-scrollbar-thumb-hover);
}
/* Static (literal) light-theme scrollbar values. Chromium does NOT reliably
   re-resolve CSS custom properties inside ::-webkit-scrollbar pseudos when the
   data-theme attribute flips AFTER first paint — Smart Lists sets data-theme in
   JS (applyTheme), not via a pre-paint <head> script like the other hubs, so the
   bar kept the dark var and rendered black. A newly-matching selector carrying
   literal values repaints correctly on the attribute change. */
html[data-theme="light"] ::-webkit-scrollbar-track { background: #eef1f7; }
html[data-theme="light"] ::-webkit-scrollbar-thumb {
  background: rgba(122, 92, 255, 0.46);
  border-color: #eef1f7;
}
html[data-theme="light"] ::-webkit-scrollbar-thumb:hover { background: rgba(0, 144, 168, 0.64); }

/* ── Anon visitor top header (challenge surfaces, /mind-print?play=,
   /neuralrun-quizzes?challenge=, /challenge/:id). Mirrors the index.html
   marketing nav so a logged-out guest doesn't see the authenticated
   app drawer chrome. Rendered by nav.js when no Supabase session is
   detected; the app drawer is skipped entirely in that branch. ── */
.nrnav-anon-bar {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(5, 5, 5, 0.82);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  font-family: 'Fira Code', monospace;
}
.nrnav-anon-inner {
  max-width: 1180px;
  margin: 0 auto;
  padding: 0.85rem 1.5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
}
.nrnav-anon-brand {
  display: inline-flex;
  align-items: center;
  line-height: 0;
  text-decoration: none;
}
.nrnav-anon-brand img {
  display: block;
  height: 36px;
  width: auto;
}
.nrnav-anon-menu {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
  gap: 1.25rem;
}
.nrnav-anon-menu a {
  font-family: 'Fira Code', monospace;
  font-size: 0.78rem;
  text-decoration: none;
  color: #858595;
  transition: color 0.15s;
}
.nrnav-anon-menu a:hover { color: #00f3ff; }
.nrnav-anon-cta {
  display: flex;
  gap: 0.5rem;
}
.nrnav-anon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: 'Fira Code', monospace;
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 1px;
  padding: 10px 18px;
  border-radius: 3px;
  text-decoration: none;
  border: 1px solid transparent;
  transition: transform 0.15s, box-shadow 0.15s, background 0.15s, border-color 0.15s;
  min-height: 40px;
}
.nrnav-anon-btn-primary {
  background: linear-gradient(135deg, #7a5cff, #9d4eff);
  color: #fff;
}
.nrnav-anon-btn-primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 18px rgba(122, 92, 255, 0.4);
}
.nrnav-anon-btn-ghost {
  background: transparent;
  color: #e0e0e0;
  border-color: #333;
}
.nrnav-anon-btn-ghost:hover {
  border-color: #00f3ff;
  color: #00f3ff;
}
.nrnav-anon-toggle { display: none; }

@media (max-width: 760px) {
  .nrnav-anon-inner { flex-wrap: wrap; }
  .nrnav-anon-toggle {
    display: inline-flex;
    flex-direction: column;
    gap: 4px;
    background: transparent;
    border: 1px solid #333;
    border-radius: 4px;
    padding: 8px 10px;
    cursor: pointer;
    order: 2;
  }
  .nrnav-anon-toggle span {
    display: block;
    width: 18px;
    height: 2px;
    background: #e0e0e0;
  }
  .nrnav-anon-menu {
    display: none;
    flex-basis: 100%;
    order: 4;
    flex-direction: column;
    padding-top: 0.75rem;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
  }
  .nrnav-anon-menu.is-open { display: flex; }
  .nrnav-anon-cta { order: 3; }
}

/* ── ANIMATED AURORA BACKGROUND ──
   Two independently-drifting soft gradient-mesh layers behind page
   content. Applies to "hub" pages (dashboard/profile/settings/admin/
   synapse/mind-print) and any page that opts in with .nr-aurora-bg
   (e.g. daily-sprint, which uses the "app" context). Self-themed app
   pages (trivia, NeuralRun Quizzes, dice, roulette, smart-lists) are NOT
   targeted — they keep their own backgrounds.
   Compositor-friendly: animates transform only; blur applied once.
   Pseudo-elements sit at z-index:-1 → above the page's base background,
   below all content, and never intercept pointer events. */
/* Flat base replaces each page's inline static radial-circle gradient.
   The dark base must sit on <html> (the ancestor): a z-index:-1 pseudo
   on <body> paints in the root's negative layer, which is BELOW body's
   own background — so an opaque body background would hide the aurora.
   Putting the base on html + making body transparent lets the pseudo
   show. :has() scopes this to hub / opt-in pages without per-page edits;
   the higher specificity also overrides each page's inline `html, body`
   gradient. */
html:has(body[data-nav-context="hub"]),
html:has(body.nr-aurora-bg) {
  /* grain tile dithers the aurora's 8-bit gradient banding (visible rings on large screens) */
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E") repeat, #050505;
}
body[data-nav-context="hub"],
body.nr-aurora-bg {
  background: transparent;
}
body[data-nav-context="hub"]::before,
body[data-nav-context="hub"]::after,
body.nr-aurora-bg::before,
body.nr-aurora-bg::after {
  content: '';
  position: fixed;
  inset: -20%;
  z-index: -1;
  pointer-events: none;
  will-change: transform;
}
body[data-nav-context="hub"]::before,
body.nr-aurora-bg::before {
  background:
    radial-gradient(38vw 38vw at 22% 30%, rgba(122, 92, 255, 0.28), 27%, transparent 80%),
    radial-gradient(30vw 30vw at 78% 22%, rgba(0, 243, 255, 0.18), 28%, transparent 84%);
  filter: blur(max(50px, 3.5vw));
  animation: nrAuroraA 28s ease-in-out infinite alternate;
}
body[data-nav-context="hub"]::after,
body.nr-aurora-bg::after {
  background:
    radial-gradient(42vw 42vw at 62% 78%, rgba(122, 92, 255, 0.18), 27%, transparent 80%),
    radial-gradient(26vw 26vw at 35% 70%, rgba(0, 243, 255, 0.12), 28%, transparent 84%);
  filter: blur(max(55px, 3.8vw));
  animation: nrAuroraB 36s ease-in-out infinite alternate;
}
@keyframes nrAuroraA {
  0%   { transform: translate3d(-5%, -4%, 0) scale(1.05) rotate(0deg); }
  100% { transform: translate3d(4%, 3%, 0)   scale(1.18) rotate(8deg); }
}
@keyframes nrAuroraB {
  0%   { transform: translate3d(3%, 4%, 0)   scale(1.10) rotate(0deg); }
  100% { transform: translate3d(-4%, -3%, 0) scale(1.00) rotate(-6deg); }
}
@media (prefers-reduced-motion: reduce) {
  body[data-nav-context="hub"]::before,
  body[data-nav-context="hub"]::after,
  body.nr-aurora-bg::before,
  body.nr-aurora-bg::after { animation: none; }
}

/* ── LIGHT BACKDROP THEME ("Crystal White") ──
   Device-local theme toggle (chosen in /settings) flips <html data-theme>
   before paint. v1 scope is deliberately narrow: the shared aurora BACKDROP
   on hub pages only. Cards, text, the game apps (Infinite/NeuralRun Quizzes/Override)
   and the marketing homepage are intentionally untouched — they keep their
   own dark styling. Higher specificity than the dark base rule above, so it
   wins without !important. Cyan is shifted toward blue so the gradient stays
   visible on a near-white base (pure cyan washes out on white). */
html[data-theme="light"]:has(body[data-nav-context="hub"]),
html[data-theme="light"]:has(body.nr-aurora-bg) {
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E") repeat, #eef1f7;
}
html[data-theme="light"] body[data-nav-context="hub"]::before,
html[data-theme="light"] body.nr-aurora-bg::before {
  background:
    radial-gradient(38vw 38vw at 22% 30%, rgba(122, 92, 255, 0.20), 27%, transparent 80%),
    radial-gradient(30vw 30vw at 78% 22%, rgba(0, 160, 255, 0.16), 28%, transparent 84%);
}
html[data-theme="light"] body[data-nav-context="hub"]::after,
html[data-theme="light"] body.nr-aurora-bg::after {
  background:
    radial-gradient(42vw 42vw at 62% 78%, rgba(122, 92, 255, 0.14), 27%, transparent 80%),
    radial-gradient(26vw 26vw at 35% 70%, rgba(0, 160, 255, 0.10), 28%, transparent 84%);
}

/* ── TOP HEADER BAR (logo + hamburger) ── */
/* HUB-ONLY page var remap. Scoped via :has() because the game apps (Infinite /
   NeuralRun Quizzes / Override) also set data-theme now — a bare html[data-theme="light"]
   (0,1,1) outranked their own :root (0,1,0) palettes and hijacked --text-main /
   --surface-card / --bg-charcoal-deep inside the games, turning their in-app text
   black on dark. Games keep their full dark palettes; only their backdrop + nav
   go light. */
html[data-theme="light"]:has(body[data-nav-context="hub"]) {
  --bg-charcoal-deep: #eef1f7;
  --surface-card: #ffffff;
  --surface-modal: #ffffff;
  --text-main: #14141c;
  --text-dim: #5a5a6a;
}

/* Nav "light island": on game pages the remap above no longer applies, but the
   nav surfaces below DO go white there — so the nav (and its toasts + feedback
   modal, which mount on body) needs its own dark text vars or it inherits the
   game's light --text-main and goes invisible-on-white. Harmless on hub pages
   (same values as the remap). */
html[data-theme="light"] .nrnav-bar,
html[data-theme="light"] .nrnav-drawer,
html[data-theme="light"] .nrnav-toast-stack,
html[data-theme="light"] .nrnav-toast,
html[data-theme="light"] .nrnav-fb-scrim,
html[data-theme="light"] .nrnav-fb-modal {
  --text-main: #14141c;
  --text-dim: #5a5a6a;
  /* Mandatory companion to --nrnav-link's dark default: #a8a8ba measures
     2.20:1 on the #f7f8fc light drawer. #4a4a5a is 8.18:1 (AAA) — also an
     improvement on the 6.37:1 the old --text-dim #5a5a6a gave here. */
  --nrnav-link: #4a4a5a;
}

/* ── LIGHT THEME: the global nav follows Crystal White too ──
   Surfaces flip to white, borders to soft gray; text goes dark via the
   light-island vars above. Only hardcoded-dark values (burger stripes, disabled
   link) and low-contrast neon accents (success-green, cyan) need explicit
   overrides. The logged-out anon header never sets data-theme — stays dark. */
html[data-theme="light"] .nrnav-bar {
  background: rgba(255, 255, 255, 0.92);
  border-bottom-color: #e2e4ec;
}
html[data-theme="light"] .nrnav-drawer {
  background: #f7f8fc;
  border-right-color: #e2e4ec;
}
html[data-theme="light"] .nrnav-drawer-brand { border-bottom-color: rgba(0, 0, 0, 0.08); }
html[data-theme="light"] .nrnav-foot { border-top-color: rgba(0, 0, 0, 0.08); }

/* Burger stripes are hardcoded light (for the always-dark bar) — go dark on the light bar. */
html[data-theme="light"] .nrnav-burger span,
html[data-theme="light"] .nrnav-burger span::before,
html[data-theme="light"] .nrnav-burger span::after { background: #14141c; }

/* Disabled link was a near-black gray → light gray so it still reads "muted" on white. */
html[data-theme="light"] .nrnav-links .nrnav-disabled { color: #b4b4c0; }

/* Plan CTA + neuron count: neon success-green fails contrast on white → darker green. */
html[data-theme="light"] .nrnav-plan-cta,
html[data-theme="light"] .nrnav-plan-cta .nrnav-plan-label,
html[data-theme="light"] .nrnav-neurons { color: #0a8f43; }
html[data-theme="light"] .nrnav-plan-cta { background: rgba(10, 143, 67, 0.08); }
html[data-theme="light"] .nrnav-plan-cta:hover { background: rgba(10, 143, 67, 0.14); }

/* Feedback button + modal accent: neon cyan washes out on white → teal. */
html[data-theme="light"] .nrnav-feedback { color: #0090a8; border-color: rgba(0, 144, 168, 0.4); }
html[data-theme="light"] .nrnav-feedback:hover { background: rgba(0, 144, 168, 0.08); border-color: #0090a8; }

/* Rail tooltip on white. The tooltip's own `color: var(--text-main)` resolves
   to near-black via the light-island vars above, so its hardcoded dark
   background would render dark-on-dark. Flip the surface instead. */
html[data-theme="light"] .nrnav-links a::after {
  background: #ffffff;
  border-color: #d8dae6;
  box-shadow: 0 6px 18px rgba(20, 20, 28, 0.16);
}

/* Toast card on white. */
html[data-theme="light"] .nrnav-toast {
  background: #ffffff;
  border-color: #e2e4ec;
  box-shadow: 0 10px 28px rgba(20, 20, 28, 0.14);
}

/* Feedback modal on white. */
html[data-theme="light"] .nrnav-fb-modal { background: #ffffff; border-color: #e2e4ec; }
html[data-theme="light"] .nrnav-fb-title { color: #0090a8; }
html[data-theme="light"] .nrnav-fb-type-btn { background: #f4f5f9; border-color: #d7dbea; }
html[data-theme="light"] .nrnav-fb-modal textarea { background: #ffffff; border-color: #d7dbea; }
html[data-theme="light"] .nrnav-fb-cancel { border-color: #d7dbea; }
html[data-theme="light"] .nrnav-fb-file { background: #ffffff; border-color: #d7dbea; }
html[data-theme="light"] .nrnav-fb-file::file-selector-button { background: #f4f5f9; border-color: #d7dbea; }
html[data-theme="light"] .nrnav-fb-admin-note { border-top-color: #e2e4ec; }

/* Logo swap: the dark wordmark (light-gray "Neural") is the default; a dark-text
   variant takes over in light mode so it reads on the white bar/drawer. Pure CSS
   so it flips instantly with the settings toggle. The anon header keeps the single
   dark logo (logged-out surfaces never enable light mode). */
/* Brand-scoped so these beat `.nrnav-bar-brand img { display:block }` (0,1,1)
   above — a bare `.nrnav-logo-light` (0,1,0) lost to it and the light logo
   leaked on dark/app pages. */
.nrnav-bar-brand .nrnav-logo-light,
.nrnav-drawer-brand .nrnav-logo-light { display: none; }
html[data-theme="light"] .nrnav-bar-brand .nrnav-logo-dark,
html[data-theme="light"] .nrnav-drawer-brand .nrnav-logo-dark { display: none; }
html[data-theme="light"] .nrnav-bar-brand .nrnav-logo-light,
html[data-theme="light"] .nrnav-drawer-brand .nrnav-logo-light { display: block; }
/* The square mark is the COLLAPSED-rail logo only — hidden everywhere else
   (mobile drawer, expanded rail), where the wordmark has room. Theme-agnostic:
   the mark reads on both light and dark drawer surfaces, so it needs no
   dark/light pair. Re-shown in the >=1024px block. */
.nrnav-drawer-brand .nrnav-logo-mark { display: none; }

.nrnav-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 52px;
  padding: 0 14px;
  background: rgba(10, 10, 14, 0.97);
  border-bottom: 1px solid rgba(122, 92, 255, 0.12);
  position: sticky;
  top: 0;
  z-index: 900;
}

/* App pages pin the bar to the VIEWPORT. position:sticky silently fails on
   app pages because their CSS sets overflow-x:hidden on html/body — that
   makes body a scroll container, so the bar sticks to body (which doesn't
   scroll) and scrolls out of view as the document (html) scrolls. Fixed is
   immune to ancestor overflow; the matching body padding-top reserves the
   bar's height, net-zero vs the old in-flow sticky bar that already took
   52px at the top. Scoped to app context so the hub layout is untouched. */
body[data-nav-context="app"] { padding-top: 52px; }
/* Anon visitors on app pages get the in-flow sticky marketing bar, NOT the
   fixed app bar — so the 52px reserve above would leave a gap that detaches the
   bar from the top. Drop it when the anon bar is present. */
body[data-nav-context="app"]:has(.nrnav-anon-bar) { padding-top: 0; }
body[data-nav-context="app"] .nrnav-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
}

/* Hybrid content pages (e.g. /learn) ship their own static .nr-topbar for anon
   visitors + SEO. When a logged-in visitor loads nav.js it injects the sticky
   app bar + drawer — hide the static topbar so there's no double header. Scoped
   to :has(.nrnav-bar) so anon (no injected bar) keeps its header untouched. */
body[data-nav-context="content"]:has(.nrnav-bar) .nr-topbar { display: none; }

/* Anti-flash for logged-in content pages: a synchronous <head> script sets
   html.nr-authed from the auth token BEFORE the static topbar paints, so the
   marketing header never blinks before deferred nav.js boots. We also reserve
   the app bar's height and pin it fixed (like app context) so the injected
   drawer bar drops into reserved space with no layout shift. Anon visitors
   never get .nr-authed, so their static topbar is untouched. */
html.nr-authed body[data-nav-context="content"] .nr-topbar { display: none; }
html.nr-authed body[data-nav-context="content"] { padding-top: 52px; }
html.nr-authed body[data-nav-context="content"] .nrnav-bar { position: fixed; top: 0; left: 0; right: 0; }
.nrnav-burger {
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid rgba(122, 92, 255, 0.25);
  border-radius: 5px;
  cursor: pointer;
  flex-shrink: 0;
  padding: 0;
}
.nrnav-burger:hover { background: rgba(122, 92, 255, 0.08); }
.nrnav-burger span,
.nrnav-burger span::before,
.nrnav-burger span::after {
  display: block;
  width: 16px;
  height: 2px;
  /* Hardcoded light — the nav bar background is always dark
     (rgba(10,10,14,0.97)) regardless of page theme, so the burger
     stripes must stay light or they invert to invisible-on-dark
     when a page enables light mode (smart-lists). */
  background: #e0e0e0;
  transition: transform 0.24s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.18s ease;
}
.nrnav-burger span { position: relative; }
.nrnav-burger span::before,
.nrnav-burger span::after {
  content: '';
  position: absolute;
  left: 0;
}
.nrnav-burger span::before { top: -5px; }
.nrnav-burger span::after { top: 5px; }

/* Hamburger -> X. Middle bar fades out; top/bottom rotate onto its axis and
   recenter, so the X sits exactly where the 3 lines were — no jump. Toggled
   by nav.js adding .nrnav-open to the button itself (mirrors the drawer's own
   open class) whenever the drawer opens, mobile or desktop alike. */
.nrnav-burger.nrnav-open span { opacity: 0; }
.nrnav-burger.nrnav-open span::before { top: 0; transform: rotate(45deg); }
.nrnav-burger.nrnav-open span::after { top: 0; transform: rotate(-45deg); }
@media (prefers-reduced-motion: reduce) {
  .nrnav-burger span,
  .nrnav-burger span::before,
  .nrnav-burger span::after { transition: none !important; }
}
.nrnav-bar-brand {
  display: inline-flex;
  align-items: center;
  height: 36px;
  text-decoration: none;
}
.nrnav-bar-brand img {
  display: block;
  width: auto;
  height: 32px;
  max-width: 150px;
  object-fit: contain;
}

/* ── DRAWER (overlay form — default: mobile + every app/tool) ── */
.nrnav-drawer {
  position: fixed;
  top: 0;
  left: 0;
  width: 230px;
  height: 100dvh;
  background: rgba(10, 10, 14, 0.99);
  border-right: 1px solid rgba(122, 92, 255, 0.12);
  display: flex;
  flex-direction: column;
  transform: translateX(-100%);
  transition: transform 0.28s cubic-bezier(0.16, 1, 0.3, 1);
  z-index: 1000;
  overflow-y: auto;
}
.nrnav-drawer.nrnav-open { transform: translateX(0); }

.nrnav-scrim {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.28s ease;
  z-index: 999;
}
.nrnav-scrim.nrnav-open { opacity: 1; pointer-events: auto; }

/* ── DRAWER INTERNALS ── */
.nrnav-drawer-brand {
  display: flex;
  align-items: center;
  padding: 1.25rem 1.25rem 1rem;
  min-height: 72px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
  text-decoration: none;
}
.nrnav-drawer-brand img {
  display: block;
  width: auto;
  height: 34px;
  max-width: 170px;
  object-fit: contain;
}
.nrnav-links {
  flex: 1;
  padding: 1rem 0;
}
/* Icon column — shared by the mobile drawer and the desktop rail, so both
   speak the same visual language (and both pick up the real icon set in one
   place once it lands). Sized down slightly from the desktop rail's 20px to
   fit the denser mobile row. */
.nrnav-ico {
  display: inline-flex;
  flex: 0 0 18px;
  width: 18px;
  height: 18px;
  align-items: center;
  justify-content: center;
}
.nrnav-ico svg { width: 18px; height: 18px; display: block; }
/* Legibility pass (2026-07-29). Was 12px / 1px tracking / #858595 at 5.45:1 in
   a ~33px row — AA-compliant on paper but hard to read on a phone, and the row
   sat under both the iOS 44px and Android 48px touch minimums. Caps are kept
   deliberately (brand), so the gains come from the multipliers that carry no
   brand meaning: size, weight, tracking, contrast, and row height.
     · 0.875rem (14px) — Gemini/ChatGPT sit at 14-16px
     · weight 600 — real on both mono families; see the note at the top
     · 0.5px tracking — 1px was 8% of the em at 12px and fragmented short words
     · #a8a8ba on the drawer = 8.45:1 (AAA) vs #858595's 5.45:1 (AA only)
     · 0.9rem block padding => ~48px rows below the rail breakpoint. The >=1024px
       block sets its own height/padding, so this is mobile + tablet only. */
.nrnav-links a,
.nrnav-links .nrnav-disabled {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0.9rem 1.25rem;
  font-family: var(--nrnav-font);
  font-size: 0.875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--nrnav-link, #a8a8ba);
  text-decoration: none;
  border-left: 2px solid transparent;
  transition: color 0.2s, background 0.2s;
}
.nrnav-links a:hover { color: var(--text-main, #e0e0e0); background: rgba(122, 92, 255, 0.06); }
.nrnav-links .nrnav-disabled { color: #3a3a4a; cursor: default; }
.nrnav-links a.nrnav-active {
  color: var(--accent-creation, #7a5cff);
  background: rgba(122, 92, 255, 0.1);
  border-left-color: var(--accent-creation, #7a5cff);
}
.nrnav-foot {
  border-top: 1px solid rgba(255, 255, 255, 0.05);
  padding: 0.85rem 1rem;
}
.nrnav-user {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.6rem;
}
.nrnav-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--accent-creation, #7a5cff), #9d4eff);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--nrnav-font);
  font-size: 0.7rem;
  font-weight: 700;
  color: #fff;
  flex-shrink: 0;
  overflow: hidden;
}
.nrnav-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.nrnav-email {
  font-family: var(--nrnav-font);
  font-size: 0.68rem;
  color: var(--text-dim, #858595);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.nrnav-neurons {
  font-family: var(--nrnav-font);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.5px;
  color: var(--accent-success, #00ff41);
  margin: 0 0 0.6rem 2px;
}
.nrnav-neurons.nrnav-neurons-low { color: var(--accent-error, #ff0055); }

/* ── Plan badge + upgrade CTA in drawer footer ── */
.nrnav-plan {
  display: flex;
  margin: 0 0 0.5rem 0;
}
/* Green button — same footprint as the Feedback / Sign Out footer buttons
   (full width, 8px padding, 0.7rem) with the dashboard "Free" badge color
   scheme. "Upgrade →" stays purple to read as the action. */
.nrnav-plan-cta {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: center;
  gap: 7px;
  text-decoration: none;
  font-family: var(--nrnav-font);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  padding: 8px;
  border-radius: 4px;
  color: var(--accent-success, #00ff41);
  background: rgba(0, 255, 65, 0.06);
  border: 1px solid currentColor;
  transition: 0.2s;
}
.nrnav-plan-cta:hover { background: rgba(0, 255, 65, 0.12); }
.nrnav-plan-cta .nrnav-plan-label { color: var(--accent-success, #00ff41); font-size: inherit; }
.nrnav-plan-upgrade { color: var(--accent-creation, #7a5cff); }
/* Plain dim label for top-tier (Power) — no upgrade target. */
.nrnav-plan-label {
  font-family: var(--nrnav-font);
  font-size: 0.72rem;
  color: var(--text-dim, #858595);
}

.nrnav-action {
  width: 100%;
  background: transparent;
  border: 1px solid rgba(122, 92, 255, 0.3);
  color: var(--text-dim, #858595);
  padding: 8px;
  font-family: var(--nrnav-font);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  cursor: pointer;
  border-radius: 4px;
  transition: 0.2s;
}
.nrnav-action:hover {
  color: var(--text-main, #e0e0e0);
  border-color: var(--accent-creation, #7a5cff);
  background: rgba(122, 92, 255, 0.06);
}
.nrnav-action.nrnav-signout {
  border-color: rgba(255, 0, 85, 0.4);
  color: var(--accent-error, #ff0055);
}
.nrnav-action.nrnav-signout:hover {
  background: rgba(255, 0, 85, 0.08);
  border-color: var(--accent-error, #ff0055);
}

/* The old per-page margin-left:220px hack is obsolete at every width —
   desktop uses the flex layout, mobile uses an overlay drawer. */
body[data-nav-context="hub"] .nr-main { margin-left: 0 !important; }

/* Was max-width:767px, widened to 1023px when the desktop rail moved to a
   1024px breakpoint. Without this the 768-1023px band fell between the two
   regimes: no rail yet, but also no pinned bar, leaving the hub bar on the
   base position:sticky that silently fails here (see below). The whole band now
   behaves exactly like mobile — fixed bar + overlay drawer. */
@media (max-width: 1023px) {
  body[data-nav-context="hub"] .nrnav-bar { width: 100%; box-sizing: border-box; }
  /* position:sticky silently fails here — the hub layout makes an ancestor a
     scroll container, so the bar sticks to a non-scrolling box and rides the
     page out of view (same trap the app context hit). Pin to the viewport with
     fixed + a 52px body reserve so content starts below the bar. Desktop
     (≥768px, bar hidden, sidebar layout) is untouched. */
  body[data-nav-context="hub"] { padding-top: 52px; }
  body[data-nav-context="hub"] .nrnav-bar { position: fixed; top: 0; left: 0; right: 0; }
}

/* ══════════════════════════════════════════════════════════════════════════
   DESKTOP RAIL (>=1024px) — the single nav surface for every context
   ──────────────────────────────────────────────────────────────────────────
   Replaces the old split where `hub` got a permanent 230px sidebar at
   >=768px while every app/tool page got only a burger + overlay drawer. Now
   all authenticated contexts render the same collapsed 60px icon rail, which
   expands on hover (peek, overlays content) or on click (pin, widens the
   gutter too). Below 1024px NOTHING here applies — the mobile bar + overlay
   drawer are untouched, which is deliberate: mobile was already right.

   Every selector is gated on `body:has(.nrnav-drawer)`. Anon visitors get the
   marketing bar and no drawer at all (nav.js returns early), so scoping to the
   drawer's presence keeps logged-out marketing pages from inheriting a 60px
   dead gutter. The same guard is used at .nrnav-anon-bar above.
   ══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 1024px) {
  /* The rail owns the brand and the toggle, so the 52px top bar is redundant.
     Removing it also hands 52px of vertical space back to the game canvases.
     padding-top needs !important to beat both the .nr-authed content rule
     (0,2,2) and nav.js's inline mobile pin, which can survive a resize. */
  body:has(.nrnav-drawer) {
    padding-top: 0 !important;
    padding-left: 60px;
  }
  body:has(.nrnav-drawer) .nrnav-bar,
  body:has(.nrnav-drawer) .nrnav-scrim { display: none; }

  /* Six stylesheets hardcode a viewport minus the now-absent 52px bar. Reclaim
     it centrally — each of these selectors outranks the bare #game-root /
     .app-container rule it overrides, so none of those files need touching.
     glowgrid.css:25, marathon.css:25, misfire.css:23, swarm.css:25,
     Digital Dice thrower.html:78, smart-lists.html:44 */
  body:has(.nrnav-drawer) #game-root { height: 100dvh; }
  body:has(.nrnav-drawer) .app-container { min-height: 100dvh; }

  /* ── HUB: permanently expanded, full width reserved ──
     Nav and content sit side by side; nothing is ever occluded. This is the
     pre-rail sidebar behaviour restored — on card-dense pages a floating peek
     was occlusion with extra steps. No transition on this gutter: it never
     changes at a fixed width, so animating it could only ever be a load-time
     flash. */
  body[data-nav-context="hub"]:has(.nrnav-drawer) { padding-left: 248px; }

  /* The old flex-child sidebar is gone; the drawer is always out of flow. The
     margin-left:0 !important at .nr-main above already neutralises the hub
     pages' inline 230px offsets. */
  body:has(.nrnav-drawer) .nrnav-drawer {
    position: fixed;
    top: 0;
    left: 0;
    transform: none;
    width: 60px;
    height: 100dvh;
    /* Tooltips fly out past the rail's right edge, so no clipping here. The
       collapsed rail is short enough not to need internal scroll, and the
       expanded state is only 248px of the same content. */
    overflow: visible;
    transition: width 0.26s cubic-bezier(0.16, 1, 0.3, 1);
  }
  body:has(.nrnav-drawer) .nrnav-drawer.nrnav-rail-wide { width: 248px; }
  /* Hub is expanded from the first frame, so it must not play the width
     transition on load — only app-context peeks animate. */
  body[data-nav-context="hub"]:has(.nrnav-drawer) .nrnav-drawer { transition: none; }

  /* ── Brand: square site icon collapsed, wordmark expanded ──
     Cropping the 437x91 wordmark into 60px sliced the "N" off mid-letter, so
     the collapsed rail gets the real square mark instead. */
  body:has(.nrnav-drawer) .nrnav-drawer-brand {
    padding: 1rem 0 1rem 18px;
    min-height: 56px;
    overflow: hidden;
  }
  body:has(.nrnav-drawer) .nrnav-drawer-brand img {
    height: 26px;
    width: auto;
    max-width: 150px;
    object-position: left center;
  }
  /* Collapsed → mark only. The wordmark pair is hidden by the base
     brand-scoped theme rules plus this; the mark is 66x64 so it stays square
     at 26px with room to spare. */
  body:has(.nrnav-drawer) .nrnav-drawer:not(.nrnav-rail-wide) .nrnav-logo-dark,
  body:has(.nrnav-drawer) .nrnav-drawer:not(.nrnav-rail-wide) .nrnav-logo-light {
    display: none;
  }
  body:has(.nrnav-drawer) .nrnav-drawer:not(.nrnav-rail-wide) .nrnav-logo-mark {
    display: block;
    height: 24px;
  }
  /* The mark's spokes render near-white — correct on the dark drawer (its
     native habitat: same asset as the favicon, always seen on dark chrome),
     but that's illegible on the Crystal White drawer background (#f7f8fc).
     There's no separate light-ink export of this asset, so give it a small
     dark chip — its actual intended backdrop — instead of sitting directly on
     white. Padding is asymmetric-safe via background-clip: the image itself
     doesn't grow, so the drawer-brand layout above is untouched. */
  html[data-theme="light"] body:has(.nrnav-drawer) .nrnav-drawer:not(.nrnav-rail-wide) .nrnav-logo-mark {
    padding: 4px;
    background: rgba(10, 10, 14, 0.94);
    border-radius: 8px;
  }

  /* ── Links: icon column is fixed, only the label reveals ──
     The icon never moves between states — that's what makes the expansion read
     as engineered rather than as a div that got wider. */
  body:has(.nrnav-drawer) .nrnav-links { padding: 0.75rem 0; }
  body:has(.nrnav-drawer) .nrnav-links a,
  body:has(.nrnav-drawer) .nrnav-links .nrnav-disabled {
    position: relative;
    display: flex;
    align-items: center;
    gap: 12px;
    /* 44px, not the mobile 48px: a mouse needs no thumb-sized target, but the
       row still has to breathe around 14px/600 text. Fixed height (not padding)
       so the collapsed rail's icons stay on an even rhythm. */
    height: 44px;
    padding: 0 0 0 18px;
    white-space: nowrap;
  }
  body:has(.nrnav-drawer) .nrnav-ico {
    display: inline-flex;
    flex: 0 0 20px;
    width: 20px;
    height: 20px;
    align-items: center;
    justify-content: center;
  }
  body:has(.nrnav-drawer) .nrnav-ico svg { width: 20px; height: 20px; display: block; }
  /* visibility (not display/width) so the label never reserves layout and never
     clips the tooltip pseudo-element on the same anchor. */
  body:has(.nrnav-drawer) .nrnav-label {
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.16s ease;
  }
  body:has(.nrnav-drawer) .nrnav-drawer.nrnav-rail-wide .nrnav-label {
    opacity: 1;
    visibility: visible;
    /* Delayed so the text fades in after the width has mostly settled instead
       of smearing across the growing box. */
    transition-delay: 0.1s;
  }

  /* ── Collapsed tooltips (CSS only — label text comes from data-label) ── */
  body:has(.nrnav-drawer) .nrnav-links a::after {
    content: attr(data-label);
    position: absolute;
    left: calc(100% + 12px);
    top: 50%;
    transform: translateY(-50%) translateX(-4px);
    padding: 5px 9px;
    font-family: var(--nrnav-font);
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--text-main, #e0e0e0);
    background: rgba(10, 10, 14, 0.98);
    border: 1px solid rgba(122, 92, 255, 0.3);
    border-radius: 4px;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.5);
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.14s ease, transform 0.14s ease;
    z-index: 1;
  }
  body:has(.nrnav-drawer) .nrnav-links a:hover::after {
    opacity: 1;
    transform: translateY(-50%) translateX(0);
  }
  /* Expanded state has real labels — a tooltip would be redundant noise. */
  body:has(.nrnav-drawer) .nrnav-drawer.nrnav-rail-wide .nrnav-links a::after { content: none; }

  /* Collapsed, the notification count has nowhere to sit, so it degrades to a
     dot pinned to the icon's corner. font-size:0 drops the digits without
     needing a second element in the markup. */
  body:has(.nrnav-drawer) .nrnav-drawer:not(.nrnav-rail-wide) .nrnav-notif-badge {
    position: absolute;
    top: 9px;
    left: 32px;
    min-width: 8px;
    width: 8px;
    height: 8px;
    padding: 0;
    margin-left: 0;
    font-size: 0;
    border-radius: 50%;
  }

  /* ── Footer: avatar always visible, identity block reveals on expand ── */
  body:has(.nrnav-drawer) .nrnav-foot { padding: 0.75rem 14px; }
  body:has(.nrnav-drawer) .nrnav-drawer:not(.nrnav-rail-wide) .nrnav-user { margin-bottom: 0; }
  body:has(.nrnav-drawer) .nrnav-drawer:not(.nrnav-rail-wide) .nrnav-email,
  body:has(.nrnav-drawer) .nrnav-drawer:not(.nrnav-rail-wide) .nrnav-neurons,
  body:has(.nrnav-drawer) .nrnav-drawer:not(.nrnav-rail-wide) .nrnav-plan,
  body:has(.nrnav-drawer) .nrnav-drawer:not(.nrnav-rail-wide) .nrnav-feedback,
  body:has(.nrnav-drawer) .nrnav-drawer:not(.nrnav-rail-wide) .nrnav-action {
    display: none;
  }
  /* Fade the footer block in so expanding doesn't snap several elements into
     existence at once. */
  body:has(.nrnav-drawer) .nrnav-drawer.nrnav-rail-wide .nrnav-foot > *:not(.nrnav-user) {
    animation: nrnav-rail-fade 0.22s ease both;
    animation-delay: 0.08s;
  }
}

@keyframes nrnav-rail-fade {
  from { opacity: 0; transform: translateY(3px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .nrnav-drawer,
  .nrnav-label,
  .nrnav-links a::after { transition: none !important; }
  .nrnav-drawer.nrnav-rail-wide .nrnav-foot > * { animation: none !important; }
}

/* ── SYNAPSE INBOX TOAST STACK (global new-message notifications) ──
   Stack lives bottom-right, mounted on demand. Container ignores
   pointer events; only the toasts themselves are interactive so the
   stack can sit over arbitrary page content without trapping clicks. */
.nrnav-toast-stack {
  position: fixed;
  bottom: 1rem;
  right: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  z-index: 1100;
  pointer-events: none;
}

.nrnav-toast {
  width: 320px;
  max-width: calc(100vw - 2rem);
  background: rgba(18, 18, 22, 0.97);
  border: 1px solid rgba(122, 92, 255, 0.3);
  border-left: 3px solid var(--accent-creation, #7a5cff);
  border-radius: 6px;
  padding: 12px 14px;
  display: flex;
  align-items: center;
  gap: 10px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6);
  cursor: pointer;
  pointer-events: auto;
  animation: nrnav-toast-in 0.25s ease-out;
}

@keyframes nrnav-toast-in {
  from { opacity: 0; transform: translateX(20px); }
  to   { opacity: 1; transform: translateX(0); }
}

.nrnav-toast.dismissing {
  animation: nrnav-toast-out 0.2s ease-in forwards;
}

@keyframes nrnav-toast-out {
  to { opacity: 0; transform: translateX(20px); }
}

.nrnav-toast-avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--accent-creation, #7a5cff), #9d4eff);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--nrnav-font);
  font-size: 0.9rem;
  font-weight: 700;
  color: #fff;
  flex-shrink: 0;
  overflow: hidden;
}

.nrnav-toast-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.nrnav-toast-body {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1;
}

.nrnav-toast-name {
  font-family: var(--nrnav-font);
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-main, #e0e0e0);
}

.nrnav-toast-message {
  font-size: 0.78rem;
  color: var(--text-dim, #858595);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.nrnav-toast-close {
  background: transparent;
  border: none;
  color: var(--text-dim, #858595);
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
  padding: 4px;
  flex-shrink: 0;
}

.nrnav-toast-close:hover {
  color: var(--accent-error, #ff0055);
}

/* ── FEEDBACK BUTTON in drawer footer ── */
.nrnav-feedback {
  width: 100%;
  background: transparent;
  border: 1px solid rgba(0, 243, 255, 0.3);
  color: var(--accent-cyan, #00f3ff);
  padding: 8px;
  font-family: var(--nrnav-font);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  cursor: pointer;
  border-radius: 4px;
  transition: 0.2s;
  margin-bottom: 0.5rem;
}
.nrnav-feedback:hover {
  background: rgba(0, 243, 255, 0.08);
  border-color: var(--accent-cyan, #00f3ff);
}

/* ── FEEDBACK MODAL (global, mounted on first open) ── */
.nrnav-fb-scrim {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.78);
  align-items: center;
  justify-content: center;
  padding: 1rem;
  z-index: 1200;
}
.nrnav-fb-scrim.open { display: flex; }

.nrnav-fb-modal {
  background: #18181f;
  border: 1px solid rgba(122, 92, 255, 0.3);
  padding: 1.6rem 1.4rem;
  width: 100%;
  max-width: 440px;
  border-radius: 4px;
  max-height: 90vh;
  overflow-y: auto;
}
.nrnav-fb-title {
  margin: 0 0 0.4rem;
  font-family: var(--nrnav-font);
  font-size: 1rem;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--accent-cyan, #00f3ff);
}
.nrnav-fb-sub {
  margin: 0 0 1.2rem;
  font-size: 0.78rem;
  color: var(--text-dim, #858595);
}
.nrnav-fb-label {
  display: block;
  font-family: var(--nrnav-font);
  font-size: 0.66rem;
  color: var(--accent-creation, #7a5cff);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin: 0.9rem 0 0.5rem;
}
.nrnav-fb-types {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.45rem;
}
.nrnav-fb-type-btn {
  background: #050505;
  border: 1px solid #333;
  color: var(--text-main, #e0e0e0);
  padding: 9px 10px;
  font-family: var(--nrnav-font);
  font-size: 0.72rem;
  letter-spacing: 0.5px;
  cursor: pointer;
  border-radius: 3px;
  text-align: left;
  transition: 0.15s;
}
.nrnav-fb-type-btn:hover { border-color: var(--accent-creation, #7a5cff); }
.nrnav-fb-type-btn.active {
  background: rgba(122, 92, 255, 0.15);
  border-color: var(--accent-creation, #7a5cff);
  color: var(--accent-creation, #7a5cff);
}
.nrnav-fb-stars {
  display: flex;
  gap: 0.3rem;
}
.nrnav-fb-stars button {
  background: transparent;
  border: none;
  color: #444;
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
  padding: 0 0.15rem;
  transition: color 0.12s;
}
.nrnav-fb-stars button:hover,
.nrnav-fb-stars button.on {
  color: var(--accent-warning, #ff9d00);
}
.nrnav-fb-modal textarea {
  width: 100%;
  background: #050505;
  border: 1px solid #333;
  color: var(--text-main, #e0e0e0);
  padding: 10px 12px;
  font-family: 'Roboto Mono', monospace;
  font-size: 0.85rem;
  resize: vertical;
  min-height: 80px;
  border-radius: 3px;
  box-sizing: border-box;
}
.nrnav-fb-modal textarea:focus {
  border-color: var(--accent-creation, #7a5cff);
  outline: none;
}
.nrnav-fb-optional {
  text-transform: none;
  letter-spacing: 0;
  color: var(--text-dim, #858595);
  opacity: 0.8;
}
.nrnav-fb-file {
  width: 100%;
  font-family: var(--nrnav-font);
  font-size: 0.72rem;
  color: var(--text-dim, #858595);
  background: #050505;
  border: 1px solid #333;
  border-radius: 3px;
  padding: 8px 10px;
  box-sizing: border-box;
  cursor: pointer;
}
.nrnav-fb-file::file-selector-button {
  font-family: var(--nrnav-font);
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-main, #e0e0e0);
  background: #1c1c24;
  border: 1px solid #444;
  border-radius: 3px;
  padding: 6px 12px;
  margin-right: 10px;
  cursor: pointer;
}
.nrnav-fb-file::file-selector-button:hover {
  border-color: var(--accent-creation, #7a5cff);
}
.nrnav-fb-filehint {
  font-family: var(--nrnav-font);
  font-size: 0.64rem;
  color: var(--text-dim, #858595);
  margin-top: 0.35rem;
}
.nrnav-fb-admin-note {
  font-family: var(--nrnav-font);
  font-size: 0.68rem;
  line-height: 1.5;
  color: var(--text-dim, #858595);
  margin: 1rem 0 0;
  padding-top: 0.85rem;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.nrnav-fb-admin-note a {
  color: var(--accent-creation, #7a5cff);
  text-decoration: none;
}
.nrnav-fb-admin-note a:hover { text-decoration: underline; }
.nrnav-fb-status {
  font-family: var(--nrnav-font);
  font-size: 0.72rem;
  margin-top: 0.7rem;
  min-height: 1em;
  color: var(--text-dim, #858595);
}
.nrnav-fb-status.err { color: var(--accent-error, #ff0055); }
.nrnav-fb-status.ok { color: var(--accent-success, #00ff41); }
.nrnav-fb-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
  margin-top: 1.2rem;
}
.nrnav-fb-cancel,
.nrnav-fb-send {
  font-family: var(--nrnav-font);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 9px 18px;
  border-radius: 3px;
  cursor: pointer;
}
.nrnav-fb-cancel {
  background: transparent;
  border: 1px solid #444;
  color: var(--text-dim, #858595);
}
.nrnav-fb-cancel:hover {
  border-color: var(--accent-creation, #7a5cff);
  color: var(--text-main, #e0e0e0);
}
.nrnav-fb-send {
  background: linear-gradient(-45deg, var(--accent-creation, #7a5cff), #9d4eff);
  border: none;
  color: #fff;
}
.nrnav-fb-send:disabled { opacity: 0.5; cursor: not-allowed; }

/* ── Global Unread Dot ── */
.nrnav-unread-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  background-color: var(--accent-creation, #7a5cff);
  border-radius: 50%;
  box-shadow: 0 0 8px var(--accent-creation, #7a5cff);
  margin-left: 6px;
  vertical-align: super;
  pointer-events: none;
}

/* ── Persistent Toast Styles ── */
.nrnav-toast--persistent {
  border-left: 4px solid #9d4eff !important;
  box-shadow: 0 10px 30px rgba(157, 78, 255, 0.25), 0 0 15px rgba(157, 78, 255, 0.1);
}

/* ── Notifications tab + panel ── */
.nrnav-notif-tab { display: inline-flex; align-items: center; }
.nrnav-notif-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  margin-left: 8px;
  font-size: 0.68rem;
  font-weight: 700;
  line-height: 1;
  color: #fff;
  background: var(--accent-creation, #7a5cff);
  border-radius: 9px;
  box-shadow: 0 0 8px rgba(122, 92, 255, 0.5);
}

.nrnav-notif-panel {
  position: fixed;
  bottom: 1rem;
  left: 1rem;
  width: 340px;
  max-width: calc(100vw - 2rem);
  max-height: min(70vh, 520px);
  display: flex;
  flex-direction: column;
  background: rgba(18, 18, 22, 0.98);
  border: 1px solid rgba(122, 92, 255, 0.3);
  border-radius: 8px;
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.65);
  z-index: 1200;
  overflow: hidden;
  animation: nrnav-toast-in 0.2s ease-out;
}
.nrnav-notif-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 12px 14px;
  font-family: var(--nrnav-font);
  font-size: 0.78rem;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--accent-creation, #7a5cff);
  border-bottom: 1px solid rgba(122, 92, 255, 0.18);
}
/* Unified platform close button — subtle circle, red on hover. */
.nrnav-notif-close {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  font-size: 1.35rem;
  /* line-height:0 + flex centering = optically centered × (baseline drift fix) */
  line-height: 0;
  box-sizing: border-box;
  color: var(--text-dim, #8a8a99);
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 50%;
  cursor: pointer;
  transition: 0.15s;
}
.nrnav-notif-close:hover { color: #fff; background: var(--accent-error, #ff0055); border-color: var(--accent-error, #ff0055); }
.nrnav-notif-close:focus-visible { outline: 2px solid var(--accent-creation, #7a5cff); outline-offset: -2px; }
.nrnav-notif-row-dot {
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  margin-top: 6px;
  border-radius: 50%;
  background: var(--accent-creation, #7a5cff);
  box-shadow: 0 0 8px var(--accent-creation, #7a5cff);
}
.nrnav-notif-list { overflow-y: auto; padding: 6px; }
.nrnav-notif-empty {
  margin: 0;
  padding: 1.2rem 0.9rem;
  text-align: center;
  color: var(--text-dim, #8a8a99);
  font-size: 0.82rem;
}
.nrnav-notif-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  padding: 10px 10px;
  background: none;
  border: 0;
  border-radius: 5px;
  text-align: left;
  cursor: pointer;
  color: var(--text-main, #e0e0e0);
  font: inherit;
}
.nrnav-notif-row:hover { background: rgba(122, 92, 255, 0.08); }
.nrnav-notif-row:focus-visible { outline: 2px solid var(--accent-creation, #7a5cff); outline-offset: -2px; }
.nrnav-notif-row-text { flex: 1 1 auto; min-width: 0; white-space: pre-line; font-size: 0.85rem; line-height: 1.4; overflow-wrap: anywhere; }
.nrnav-notif-row-time { flex-shrink: 0; font-size: 0.7rem; color: var(--text-dim, #8a8a99); font-family: var(--nrnav-font); }

html[data-theme="light"] .nrnav-notif-panel {
  background: #fff;
  border-color: rgba(122, 92, 255, 0.25);
  box-shadow: 0 16px 40px rgba(20, 20, 28, 0.12);
}
html[data-theme="light"] .nrnav-notif-head { border-bottom-color: #e2e4ec; }
html[data-theme="light"] .nrnav-notif-row { color: #14141c; }
html[data-theme="light"] .nrnav-notif-row:hover { background: rgba(122, 92, 255, 0.08); }
html[data-theme="light"] .nrnav-notif-row-time,
html[data-theme="light"] .nrnav-notif-empty,
html[data-theme="light"] .nrnav-notif-close { color: #5a5a68; }
html[data-theme="light"] .nrnav-notif-close { background: rgba(0, 0, 0, 0.04); border-color: rgba(0, 0, 0, 0.1); }
html[data-theme="light"] .nrnav-notif-close:hover { color: #fff; background: var(--accent-error, #ff0055); border-color: var(--accent-error, #ff0055); }
html[data-theme="light"] .nrnav-notif-close:hover { color: #14141c; }

.nrnav-toast--persistent .nrnav-toast-close {
  color: var(--text-main, #e0e0e0) !important;
  text-shadow: 0 0 4px rgba(255, 255, 255, 0.4);
}

.nrnav-toast-message-wrap {
  white-space: pre-wrap !important;
  overflow: visible !important;
  text-overflow: clip !important;
}

/* --- Quick Chat FAB + connections popover --- */
.nrnav-chat-fab {
  position: fixed;
  right: calc(1rem + env(safe-area-inset-right));
  bottom: calc(1rem + env(safe-area-inset-bottom));
  z-index: 950;
  width: 56px;
  height: 56px;
  border: 1px solid rgba(0, 243, 255, 0.35);
  border-radius: 50%;
  background: linear-gradient(135deg, var(--accent-creation, #7a5cff), #9d4eff);
  color: #fff;
  box-shadow: 0 12px 32px rgba(122, 92, 255, 0.42), 0 0 18px rgba(0, 243, 255, 0.18);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.45rem;
  line-height: 1;
  cursor: pointer;
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}

html[data-theme="light"] .nrnav-chat-fab {
  border-color: rgba(0, 144, 168, 0.36);
  background: linear-gradient(135deg, #6f57ef, #8846e8);
  color: #fff;
  box-shadow: 0 12px 28px rgba(95, 75, 205, 0.25), 0 0 14px rgba(0, 144, 168, 0.12);
}

.nrnav-chat-fab:hover {
  transform: translateY(-2px);
  border-color: var(--accent-cyan, #00f3ff);
  box-shadow: 0 16px 36px rgba(122, 92, 255, 0.5), 0 0 22px rgba(0, 243, 255, 0.24);
}

html[data-theme="light"] .nrnav-chat-fab:hover {
  border-color: #0090a8;
  box-shadow: 0 16px 32px rgba(95, 75, 205, 0.3), 0 0 18px rgba(0, 144, 168, 0.16);
}

.nrnav-chat-fab:focus-visible {
  outline: 2px solid var(--accent-cyan, #00f3ff);
  outline-offset: 3px;
}

html[data-theme="light"] .nrnav-chat-fab:focus-visible {
  outline-color: #0090a8;
}

.nrnav-chat-fab-badge {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--accent-error, #ff0055);
  color: #fff;
  border: 2px solid #0a0a0e;
  box-shadow: 0 0 10px rgba(255, 0, 85, 0.5);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--nrnav-font);
  font-size: 0.65rem;
  font-weight: 700;
  line-height: 1;
  box-sizing: border-box;
}

html[data-theme="light"] .nrnav-chat-fab-badge {
  background: #d90046;
  color: #fff;
  border-color: #ffffff;
  box-shadow: 0 0 8px rgba(217, 0, 70, 0.34);
}

.nrnav-chat-pop {
  position: fixed;
  right: calc(1rem + env(safe-area-inset-right));
  bottom: calc(84px + env(safe-area-inset-bottom));
  z-index: 951;
  width: min(320px, calc(100vw - 32px));
  max-height: min(520px, calc(100vh - 116px));
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  padding: 0.95rem;
  border-radius: 8px;
  background: rgba(18, 18, 22, 0.98);
  border: 1px solid rgba(122, 92, 255, 0.34);
  box-shadow: 0 18px 42px rgba(0, 0, 0, 0.62), 0 0 22px rgba(122, 92, 255, 0.12);
  color: var(--text-main, #e0e0e0);
  font-family: var(--nrnav-font);
  transform: translateY(8px);
  opacity: 0;
  transition: opacity 0.18s ease, transform 0.18s ease;
}

html[data-theme="light"] .nrnav-chat-pop {
  background: #ffffff;
  border-color: #d7dbea;
  box-shadow: 0 18px 38px rgba(20, 20, 28, 0.16), 0 0 18px rgba(95, 75, 205, 0.08);
  color: #14141c;
}

.nrnav-chat-pop--open {
  transform: translateY(0);
  opacity: 1;
}

html[data-theme="light"] .nrnav-chat-pop--open {
  color: #14141c;
}

.nrnav-chat-pop-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  color: var(--text-main, #e0e0e0);
  font-size: 0.82rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

html[data-theme="light"] .nrnav-chat-pop-header {
  color: #14141c;
}

.nrnav-chat-pop-close {
  width: 28px;
  height: 28px;
  border: 1px solid rgba(122, 92, 255, 0.24);
  border-radius: 6px;
  background: rgba(122, 92, 255, 0.08);
  color: var(--text-dim, #858595);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.15rem;
  line-height: 1;
  cursor: pointer;
}

html[data-theme="light"] .nrnav-chat-pop-close {
  border-color: #d7dbea;
  background: #f4f5f9;
  color: #5a5a6a;
}

.nrnav-chat-pop-close:hover {
  border-color: var(--accent-error, #ff0055);
  color: var(--accent-error, #ff0055);
  background: rgba(255, 0, 85, 0.08);
}

html[data-theme="light"] .nrnav-chat-pop-close:hover {
  border-color: #d90046;
  color: #d90046;
  background: rgba(217, 0, 70, 0.08);
}

.nrnav-chat-search {
  width: 100%;
  min-height: 38px;
  box-sizing: border-box;
  border: 1px solid rgba(122, 92, 255, 0.28);
  border-radius: 6px;
  background: rgba(5, 5, 5, 0.72);
  color: var(--text-main, #e0e0e0);
  padding: 0 0.75rem;
  font-family: var(--nrnav-font);
  font-size: 0.78rem;
}

html[data-theme="light"] .nrnav-chat-search {
  border-color: #d7dbea;
  background: #ffffff;
  color: #14141c;
}

.nrnav-chat-search::placeholder {
  color: var(--text-dim, #858595);
}

html[data-theme="light"] .nrnav-chat-search::placeholder {
  color: #707084;
}

.nrnav-chat-search:focus {
  outline: none;
  border-color: var(--accent-cyan, #00f3ff);
  box-shadow: 0 0 0 3px rgba(0, 243, 255, 0.08);
}

html[data-theme="light"] .nrnav-chat-search:focus {
  border-color: #0090a8;
  box-shadow: 0 0 0 3px rgba(0, 144, 168, 0.1);
}

.nrnav-chat-list {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  max-height: min(50vh, 360px);
  overflow-y: auto;
  padding-right: 2px;
}

html[data-theme="light"] .nrnav-chat-list {
  scrollbar-color: var(--nr-scrollbar-thumb) var(--nr-scrollbar-track);
}

.nrnav-chat-row {
  width: 100%;
  min-height: 48px;
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0.45rem 0.55rem;
  border: 1px solid transparent;
  border-radius: 7px;
  background: transparent;
  color: var(--text-main, #e0e0e0);
  text-align: left;
  cursor: pointer;
  box-sizing: border-box;
}

html[data-theme="light"] .nrnav-chat-row {
  border-color: transparent;
  background: transparent;
  color: #14141c;
}

.nrnav-chat-row:hover {
  background: rgba(122, 92, 255, 0.12);
  border-color: rgba(122, 92, 255, 0.22);
}

html[data-theme="light"] .nrnav-chat-row:hover {
  background: rgba(95, 75, 205, 0.08);
  border-color: rgba(95, 75, 205, 0.18);
}

.nrnav-chat-row:focus-visible {
  outline: 2px solid var(--accent-cyan, #00f3ff);
  outline-offset: 2px;
}

html[data-theme="light"] .nrnav-chat-row:focus-visible {
  outline-color: #0090a8;
}

.nrnav-chat-row-avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--accent-creation, #7a5cff), #9d4eff);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  overflow: hidden;
  font-size: 0.85rem;
  font-weight: 700;
}

html[data-theme="light"] .nrnav-chat-row-avatar {
  background: linear-gradient(135deg, #6f57ef, #8846e8);
  color: #fff;
}

.nrnav-chat-row-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

html[data-theme="light"] .nrnav-chat-row-avatar img {
  background: #eef1f7;
}

.nrnav-chat-row-name {
  min-width: 0;
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-main, #e0e0e0);
  font-size: 0.8rem;
}

html[data-theme="light"] .nrnav-chat-row-name {
  color: #14141c;
}

.nrnav-chat-row-unread {
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--accent-error, #ff0055);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.65rem;
  font-weight: 700;
  line-height: 1;
}

html[data-theme="light"] .nrnav-chat-row-unread {
  background: #d90046;
  color: #fff;
}

.nrnav-chat-empty {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.45rem;
  padding: 0.9rem 0.55rem;
  color: var(--text-dim, #858595);
  font-size: 0.78rem;
}

html[data-theme="light"] .nrnav-chat-empty {
  color: #5a5a6a;
}

.nrnav-chat-empty a {
  color: var(--accent-cyan, #00f3ff);
  text-decoration: none;
}

html[data-theme="light"] .nrnav-chat-empty a {
  color: #007f96;
}

.nrnav-chat-empty a:hover {
  color: var(--text-main, #e0e0e0);
}

html[data-theme="light"] .nrnav-chat-empty a:hover {
  color: #14141c;
}

@media (max-width: 600px) {
  .nrnav-chat-fab {
    right: calc(0.9rem + env(safe-area-inset-right));
    /* 72px → 47px: nudge the FAB 25px closer to the viewport bottom on mobile. */
    bottom: calc(47px + env(safe-area-inset-bottom));
  }

  html[data-theme="light"] .nrnav-chat-fab {
    color: #fff;
  }

  .nrnav-chat-pop {
    right: calc(0.9rem + env(safe-area-inset-right));
    bottom: calc(140px + env(safe-area-inset-bottom));
    max-height: calc(100vh - 168px);
  }

  html[data-theme="light"] .nrnav-chat-pop {
    color: #14141c;
  }
}

@media (prefers-reduced-motion: reduce) {
  .nrnav-chat-fab,
  .nrnav-chat-pop {
    transition: none;
  }

  html[data-theme="light"] .nrnav-chat-fab,
  html[data-theme="light"] .nrnav-chat-pop {
    transition: none;
  }
}

/* --- Chat slide-panel light-theme overrides (global) ---
   The chat panel's BASE (dark) styles live in synapse.css, which nav.js
   injects on demand so the panel is styled on every authenticated page.
   These light-theme overrides previously lived inline in synapse.html and
   only applied on /synapse; hosting them here in nav.css (loaded on every
   page) makes the panel theme-aware wherever the site-wide FAB/toast opens
   it. They mirror synapse.html's inline rules verbatim. The
   html[data-theme="light"] specificity wins over the injected synapse.css
   base regardless of stylesheet load order. */
html[data-theme="light"] .synapse-chat-panel {
  background: #ffffff;
  border-left-color: rgba(122, 92, 255, 0.22);
  box-shadow: -10px 0 35px rgba(20, 20, 28, 0.16);
}

html[data-theme="light"] .synapse-chat-panel .chat-header,
html[data-theme="light"] .synapse-chat-panel .chat-composer {
  background: #ffffff;
  border-color: #e2e4ec;
}

/* Friend name was washed out: base color is the dark-theme light-grey plus a
   purple glow. Pin it to the dark ink and drop the glow on Crystal White. */
html[data-theme="light"] .synapse-chat-panel .chat-friend-name {
  color: #14141c;
  text-shadow: none;
}

/* Quick-actions (Issue a Duel) band defaults to the dark surface card — gave a
   black strip above the composer on light theme. */
html[data-theme="light"] .synapse-chat-panel .chat-quick-actions {
  background: #ffffff;
  border-top-color: #e2e4ec;
}

html[data-theme="light"] .synapse-chat-panel .chat-input {
  background: #ffffff !important; /* base is --surface-modal (dark) — the field stayed black without this */
  border-color: #d7dbea !important;
  color: var(--text-main, #14141c) !important;
}

html[data-theme="light"] .synapse-chat-panel .chat-message.message-own .chat-message-bubble {
  background: rgba(122, 92, 255, 0.12);
  color: var(--text-main, #14141c);
}

html[data-theme="light"] .synapse-chat-panel .chat-message.message-friend .chat-message-bubble,
html[data-theme="light"] .synapse-chat-panel .chat-card {
  background: #f8f9fc;
  border-color: #e2e4ec;
  color: var(--text-main, #14141c);
}

html[data-theme="light"] .synapse-chat-panel .chat-message-bubble a:not(.chat-message-mindprint-btn):not(.chat-card-cta):hover {
  color: #5b42c8;
}
