/* Self-hosted fonts (already shipped with the site) — no external requests */
@font-face { font-family:'Inter'; font-style:normal; font-weight:400; font-display:swap; src:url('../fonts/inter-400.woff2') format('woff2'); }
@font-face { font-family:'Inter'; font-style:normal; font-weight:500; font-display:swap; src:url('../fonts/inter-500.woff2') format('woff2'); }
@font-face { font-family:'Inter'; font-style:normal; font-weight:600; font-display:swap; src:url('../fonts/inter-600.woff2') format('woff2'); }
@font-face { font-family:'Inter'; font-style:normal; font-weight:700; font-display:swap; src:url('../fonts/inter-700.woff2') format('woff2'); }
@font-face { font-family:'Orbitron'; font-style:normal; font-weight:600; font-display:swap; src:url('../fonts/orbitron-600.woff2') format('woff2'); }
@font-face { font-family:'Orbitron'; font-style:normal; font-weight:700; font-display:swap; src:url('../fonts/orbitron-700.woff2') format('woff2'); }
@font-face { font-family:'Orbitron'; font-style:normal; font-weight:800; font-display:swap; src:url('../fonts/orbitron-800.woff2') format('woff2'); }

/* =========================================================
   3adooli — Kick variety streamer
   Same layout/structure as the wagsite build, reskinned
   dark + neon (colours from the room photo & 3D emblem),
   over a nebula sky with faint scattered emblems.
   ========================================================= */

* { margin: 0; padding: 0; box-sizing: border-box; }

:root {
  /* Palette (pulled from the photos) */
  --primary-color: #7c3bff;     /* electric violet */
  --primary-dark: #5a1fe0;
  --primary-light: #a06bff;
  --secondary-color: #53fc18;   /* Kick green */
  --secondary-dark: #45d613;
  --accent-color: #c14bff;      /* neon magenta */
  --accent-light: #4bb8ff;      /* neon blue */

  --bg: #08060f;
  --bg-2: #0d0a1c;
  --surface: rgba(24, 17, 48, 0.72);
  --surface-solid: #150f2b;
  --line: rgba(124, 59, 255, 0.22);
  --line-strong: rgba(124, 59, 255, 0.45);

  --text-primary: #efeaff;
  --text-secondary: #b9b0d6;
  --text-muted: #8b81a8;

  --font-primary: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-heading: 'Orbitron', 'Inter', system-ui, sans-serif;

  --spacing-xs: 0.5rem;
  --spacing-sm: 1rem;
  --spacing-md: 2rem;
  --spacing-lg: 3rem;
  --spacing-xl: 4rem;

  --transition-fast: 0.2s ease;
  --transition-normal: 0.3s ease;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  --radius: 16px;
  --glow: 0 0 22px rgba(124, 59, 255, 0.55);
  --glow-soft: 0 0 40px rgba(124, 59, 255, 0.28);
  --shadow-sm: 0 4px 14px rgba(0, 0, 0, 0.4);
  --shadow-md: 0 10px 30px rgba(0, 0, 0, 0.5);
  --shadow-lg: 0 20px 50px rgba(0, 0, 0, 0.6);
}

html { scroll-padding-top: 90px; }
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }

body {
  font-family: var(--font-primary);
  color: var(--text-primary);
  line-height: 1.65;
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  min-height: 100vh;
}

/* ---- Atmosphere: nebula sky + scattered emblems (fixed, cheap) ---- */
.sky, .sky-emblems {
  position: fixed; inset: -6% -6% -6% -6%;
  z-index: -2; pointer-events: none;
}
.sky {
  background: #06040c url('../images/nebula.webp') center/cover no-repeat;
  animation: skyDrift 60s ease-in-out infinite alternate;
}
.sky-emblems {
  z-index: -1;
  background: url('../images/emblem-scatter.webp') 0 0 repeat;
  background-size: 620px;
  opacity: 0.5;
  animation: emblemDrift 90s linear infinite;
}
@keyframes skyDrift {
  from { transform: scale(1.06) translate(-1%, -1%); }
  to   { transform: scale(1.12) translate(1.5%, 1.5%); }
}
@keyframes emblemDrift {
  from { background-position: 0 0; }
  to   { background-position: 620px 900px; }
}

img { max-width: 100%; height: auto; display: block; }

a { color: var(--primary-light); text-decoration: none; transition: color var(--transition-fast); }
a:hover { color: var(--accent-color); }

h1, h2, h3, h4 { font-family: var(--font-heading); line-height: 1.12; letter-spacing: -0.02em; }

.container { width: min(92%, 1200px); margin: 0 auto; }

.header, main, .footer { position: relative; z-index: 1; }

.skip-link {
  position: absolute; top: -80px; left: 12px; z-index: 10001;
  background: var(--primary-color); color: #fff; padding: .7rem 1.1rem;
  border-radius: 8px; font-weight: 700;
}
.skip-link:focus { top: 12px; }

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

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
.text-center { text-align: center; }

/* =========================================================
   Intro splash — Keith Locks style
   ========================================================= */
#intro {
  position: fixed; inset: 0; z-index: 10000;
  display: grid; place-items: center; cursor: pointer;
  background: #06040c url('../images/nebula.webp') center/cover no-repeat;
  transition: opacity .8s var(--ease), visibility .8s var(--ease);
}
#intro::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(700px 500px at 50% 42%, rgba(124,59,255,.25), rgba(6,4,12,.75) 70%);
}
#intro.done { opacity: 0; visibility: hidden; pointer-events: none; }

.intro-stage { position: relative; text-align: center; padding: 1.5rem; }
.intro-emblem {
  width: clamp(120px, 30vw, 190px); margin: 0 auto 1.2rem;
   filter: drop-shadow(0 0 28px rgba(124,59,255,.85));
  animation: introUp 1s var(--ease) both;
}
.intro-word {
  width: clamp(230px, 62vw, 400px); margin: 0 auto;
   filter: drop-shadow(0 0 22px rgba(160,107,255,.6));
  animation: introUp 1s var(--ease) .3s both;
}
.intro-tag {
  margin-top: 1.1rem; font-family: var(--font-heading); font-weight: 600;
  letter-spacing: .42em; text-transform: uppercase; font-size: .74rem;
  color: var(--primary-light); animation: introUp 1s var(--ease) .55s both;
}
.intro-bar {
  width: min(240px, 60vw); height: 3px; margin: 1.7rem auto 1rem;
  border-radius: 999px; overflow: hidden; background: rgba(124,59,255,.18);
}
.intro-bar span {
  display: block; height: 100%; width: 0;
  background: linear-gradient(90deg, var(--primary-color), var(--accent-color));
  box-shadow: 0 0 14px var(--primary-color);
  animation: introLoad 2.2s var(--ease) .2s forwards;
}
.intro-hint {
  color: var(--text-muted); font-size: .82rem; letter-spacing: .12em;
  text-transform: uppercase; animation: introPulse 2s ease-in-out .8s infinite;
}
@keyframes introUp { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes introLoad { to { width: 100%; } }
@keyframes introPulse { 0%,100% { opacity: .45; } 50% { opacity: 1; } }

/* =========================================================
   Header & navigation  (wagsite structure)
   ========================================================= */
.header {
  background: rgba(9, 6, 18, 0.72);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 1000;
}
.nav { display: flex; justify-content: space-between; align-items: center; padding: var(--spacing-sm) 0; }

.logo {
  display: inline-flex; align-items: center; gap: .55rem;
  font-family: var(--font-heading); font-weight: 800; font-size: 1.4rem;
  color: var(--text-primary);
}
.logo b { color: var(--primary-light); }
.logo:hover { color: var(--text-primary); }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .3; } }

/* =========================================================
   Buttons
   ========================================================= */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  min-width: 180px; min-height: 52px; padding: .85rem 1.6rem; border-radius: 999px;
  font-family: var(--font-heading); font-weight: 700; font-size: .98rem;
  cursor: pointer; border: 1px solid transparent; white-space: nowrap;
  transition: transform .18s var(--ease), box-shadow .25s var(--ease), background .2s, color .2s;
}
.btn:hover { transform: translateY(-3px); }
.btn:active { transform: translateY(0); }
.btn-primary { background: linear-gradient(135deg, var(--primary-color), var(--accent-color)); color: #fff; box-shadow: var(--glow); }
.btn-primary:hover { color: #fff; box-shadow: 0 0 32px rgba(124,59,255,.8); }
.btn-secondary { background: var(--secondary-color); color: #06110a; box-shadow: 0 0 20px rgba(83,252,24,.45); }
.btn-secondary:hover { color: #06110a; background: #6dff3a; box-shadow: 0 0 30px rgba(83,252,24,.7); }
.btn-light { background: rgba(124,59,255,.1); color: var(--text-primary); border-color: var(--line-strong); }
.btn-light:hover { color: #fff; border-color: var(--primary-color); box-shadow: var(--glow-soft); }

/* =========================================================
   Hero (home)  — wagsite structure
   ========================================================= */
.hero-home { text-align: center; padding: var(--spacing-lg) 0 var(--spacing-sm); }

/* Full-bleed: breaks out of .container's max-width so the room
   photo runs the whole width of the screen. body already has
   overflow-x:hidden, so 100vw can't open a horizontal scrollbar
   on platforms where vw counts the scrollbar's width. */
.hero-featured {
  width: 100vw;
  max-width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
}
.hero-picture { display: block; position: relative; isolation: isolate; border-radius: 0; overflow: hidden; border: 0; border-top: 1px solid var(--line-strong); border-bottom: 1px solid var(--line-strong); box-shadow: var(--shadow-lg), 0 0 60px rgba(124,59,255,.18); }
.hero-picture::after { content: ''; position: absolute; inset: 0; pointer-events: none; background: linear-gradient(180deg, rgba(0,0,0,0) 55%, rgba(6,4,12,.7) 100%); }
.hero-picture img { display: block; width: 100%; height: clamp(300px, 50vw, 620px); object-fit: cover; object-position: center; }

.eyebrow {
  font-family: var(--font-heading); font-weight: 600; font-size: .74rem;
  letter-spacing: .38em; text-transform: uppercase; color: var(--primary-light);
  text-align: center; margin-bottom: .9rem;
}

/* =========================================================
   Sections
   ========================================================= */
.section { padding: var(--spacing-xl) 0; }
.section-title { font-family: var(--font-heading); font-size: clamp(1.7rem, 4vw, 2.4rem); font-weight: 800; text-align: center; margin-bottom: var(--spacing-sm); color: var(--text-primary); }
.section-intro { text-align: center; font-size: 1.05rem; color: var(--text-secondary); margin: 0 auto var(--spacing-lg); max-width: 640px; }
.service-card { background: var(--surface); backdrop-filter: blur(8px); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--spacing-md); text-align: center; transition: transform .2s var(--ease), border-color .2s, box-shadow .25s; }
.service-card:hover { transform: translateY(-4px); border-color: var(--primary-color); box-shadow: var(--glow-soft); }
.service-icon { font-size: 2.6rem; margin-bottom: var(--spacing-xs); }
.service-card h3 { color: var(--text-primary); font-size: 1.25rem; margin-bottom: .5rem; }
.service-card p { color: var(--text-secondary); font-size: .95rem; }
.card { background: var(--surface); backdrop-filter: blur(8px); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--spacing-md); transition: transform .2s var(--ease), border-color .2s, box-shadow .25s; }
.card:hover { transform: translateY(-4px); border-color: var(--primary-color); box-shadow: var(--glow-soft); }
.card h3 { color: var(--text-primary); margin-bottom: .6rem; font-size: 1.3rem; }
.card p { color: var(--text-secondary); }
.social-card {
  display: flex; align-items: center; gap: .9rem; padding: 1.05rem 1.15rem;
  border-radius: var(--radius); background: var(--surface); backdrop-filter: blur(8px);
  border: 1px solid var(--line); color: var(--text-primary);
  transition: transform .2s var(--ease), border-color .2s, box-shadow .25s;
}
.social-card:hover { transform: translateY(-4px); color: var(--text-primary); border-color: var(--primary-color); box-shadow: var(--glow-soft); }
.social-card .ico { flex: 0 0 auto; width: 48px; height: 48px; border-radius: 13px; display: grid; place-items: center; background: rgba(124,59,255,.12); border: 1px solid var(--line); }
.social-card .ico svg { width: 25px; height: 25px; }
.social-card .txt b { display: block; font-family: var(--font-heading); font-weight: 700; font-size: 1.02rem; }
.social-card .txt span { color: var(--text-muted); font-size: .86rem; word-break: break-all; }
.s-kick .ico { color: var(--secondary-color); border-color: rgba(83,252,24,.4); background: rgba(83,252,24,.1); }
.s-discord .ico { color: #8ea1ff; }
.s-x .ico { color: #ffffff; }
.s-telegram .ico { color: #4bb8ff; }
.s-tiktok .ico { color: #ff5c8a; }
.s-instagram .ico { color: #ff77c2; }

/* =========================================================
   Band / CTA
   ========================================================= */
.band {
  position: relative; overflow: hidden; border-radius: 22px;
  padding: clamp(2rem, 5vw, 3.4rem);
  background: radial-gradient(600px 300px at 85% 0%, rgba(124,59,255,.4), transparent 60%), rgba(28, 20, 64, 0.7);
  backdrop-filter: blur(8px); border: 1px solid var(--line-strong);
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1.6rem;
}
.band h2 { font-size: clamp(1.6rem, 4vw, 2.3rem); font-weight: 800; }
.band p { color: var(--text-secondary); margin-top: .6rem; max-width: 440px; }
.band-actions { display: flex; gap: .8rem; flex-wrap: wrap; }

/* =========================================================
   Stake code + leaderboard
   ========================================================= */
.code-box {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem;
  background: var(--surface); border: 1px dashed var(--line-strong); border-radius: var(--radius);
  padding: 1.4rem 1.6rem; max-width: 560px; margin: 0 auto;
}
.code-box .code { font-family: var(--font-heading); font-weight: 800; font-size: clamp(1.6rem,5vw,2.4rem); letter-spacing: .12em; color: var(--secondary-color); text-shadow: 0 0 18px rgba(83,252,24,.5); }
.copy-btn { background: rgba(124,59,255,.14); border: 1px solid var(--line-strong); color: var(--text-primary); border-radius: 999px; padding: .6rem 1.2rem; font-weight: 700; cursor: pointer; font-family: var(--font-heading); transition: all .2s var(--ease); }
.copy-btn:hover { background: var(--primary-color); color: #fff; box-shadow: var(--glow); }
.copy-btn.copied { background: var(--secondary-color); color: #06110a; border-color: var(--secondary-color); }

/* =========================================================
   Page hero (subpages)
   ========================================================= */
.page-hero { padding: var(--spacing-xl) 0 var(--spacing-md); text-align: center; }
.page-title { font-family: var(--font-heading); font-size: clamp(2rem, 5vw, 3rem); font-weight: 800; }
.page-subtitle { color: var(--text-secondary); font-size: 1.15rem; margin-top: .7rem; max-width: 600px; margin-inline: auto; }
.prose { max-width: 760px; margin: 0 auto; }
.prose p { color: var(--text-secondary); margin-bottom: 1.1rem; }

/* =========================================================
   Footer  (wagsite structure)
   ========================================================= */
.footer { border-top: 1px solid var(--line); background: rgba(9, 6, 18, 0.82); backdrop-filter: blur(10px); padding: var(--spacing-lg) 0 var(--spacing-sm); margin-top: var(--spacing-md); }
.footer-grid { display: grid; grid-template-columns: 1.4fr 1fr 1.4fr; gap: var(--spacing-md); }
.footer-column h3 { font-family: var(--font-heading); font-size: 1.05rem; margin-bottom: var(--spacing-sm); color: var(--text-primary); }
.footer-brand img { height: 34px; margin-bottom: .9rem;  filter: drop-shadow(0 0 12px rgba(124,59,255,.6)); }
.footer-column p { color: var(--text-secondary); font-size: .92rem; margin-bottom: .5rem; }
.footer-links { list-style: none; }
.footer-links li { margin-bottom: .5rem; }
.footer-links a { color: var(--text-secondary); font-size: .92rem; }
.footer-links a:hover { color: var(--text-primary); }
.social-link:hover { transform: translateY(-3px); color: var(--text-primary); border-color: var(--primary-color); box-shadow: var(--glow); }

.footer-bottom { margin-top: var(--spacing-md); padding-top: var(--spacing-sm); border-top: 1px solid var(--line); text-align: center; color: var(--text-muted); font-size: .84rem; }
.footer-bottom a { color: var(--primary-light); }

/* =========================================================
   Responsive
   ========================================================= */
@media (max-width: 900px) {
  .footer-grid { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 768px) {

  .band { flex-direction: column; align-items: flex-start; text-align: left; }
}

@media (max-width: 480px) {
  .footer-grid { grid-template-columns: 1fr; }
  .btn { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
  .sky, .sky-emblems { animation: none; }
}
.acct-login-btn, .acct-btn-primary {
  background: linear-gradient(135deg, var(--primary-color), var(--accent-color)) !important;
  color: #fff !important; border: 0 !important;
}
.acct-login-btn:hover, .acct-btn-primary:hover { box-shadow: 0 0 26px rgba(124,59,255,.7) !important; }
.acct-btn-kick { background: var(--secondary-color) !important; color: #06110a !important; }

/* =========================================================
   Universal "glow underneath" — every button and every link on
   the site gets the always-on breathing underline the footer's
   social emblems have, regardless of shape (icon circles, pill
   buttons, plain text links, nav items). Requested: "every
   button or link just like the footer." Opt out with
   .no-glow-underline on an individual element if one ever needs
   to be bare (none currently do).
   ========================================================= */
@keyframes uGlowBreath {
  0%, 100% { opacity: .8; }
  50%      { opacity: 1; }
}

/* Base: every link and button, one shared site accent by default.
   Kept to element-only specificity (0,0,1) on purpose so the
   brand-color and opt-out overrides below — which all carry a class
   or attribute selector (0,1,x) — reliably win the cascade. */
a, button {
  position: relative;
  --u-glow: var(--primary-light);
}

/* The LED strip in the room photo: a hot near-white line of
   source, the strip's own saturated colour bleeding just under
   it, then a wide soft wash thrown across the floor. The earlier
   version had only the wash, which is why it read as a sourceless
   smudge — a real strip light is visibly a bright *line* first
   and a glow second. Blur keeps every edge undefined, and the
   radial mask dissolves the sides so it never has a silhouette. */
a::after, button::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 100%;
  width: 128%;
  height: 46px;
  transform: translateX(-50%);
  transform-origin: 50% 0%;
  background:
    /* the hot core of the strip, right at the contact edge */
    linear-gradient(to bottom, rgba(255,255,255,.92) 0%, rgba(255,255,255,0) 7%),
    /* its saturated colour bleeding just below the source */
    linear-gradient(to bottom, var(--u-glow) 0%, transparent 32%),
    /* the wash spilling out across the floor */
    radial-gradient(ellipse 66% 100% at 50% 0%, var(--u-glow) 0%, transparent 74%);
  -webkit-mask-image: radial-gradient(ellipse 62% 100% at 50% 0%, #000 12%, transparent 78%);
  mask-image: radial-gradient(ellipse 62% 100% at 50% 0%, #000 12%, transparent 78%);
  filter: blur(4px);
  opacity: .62;
  pointer-events: none;
  animation: uGlowBreath 2.8s ease-in-out infinite;
  transition: opacity .25s var(--ease), transform .25s var(--ease);
}

a:hover::after, a:focus-visible::after,
button:hover::after, button:focus-visible::after {
  opacity: .85;
  transform: translateX(-50%) scaleY(1.25);
}

/* Opt-outs: the visually-hidden skip link and anything explicitly
   marked .no-glow-underline (none currently) get no glow at all. */
.skip-link::after, .no-glow-underline::after {
  content: none;
}

/* Nav items, footer links, submenu links etc. are inline by default —
   make them inline-block so bottom/position:relative actually place
   the glow under the visible text/icon instead of the line box. */
.nav-menu a, .nav-menu button,
.footer-links a,
.submenu a,
.social-links a,
.logo {
  display: inline-block;
}

/* Color rule: anything that points at a real platform gets that
   platform's own brand color (matches its "og icon"), wherever it
   shows up on the site — nav, hero, footer emblem, social card, JS
   account buttons. Everything else (internal links, generic buttons,
   nav/footer text, the logo) keeps the shared site accent above, so
   it all reads as one consistent family instead of a rainbow of
   one-offs. Each selector below carries a class or attribute, which
   outranks the plain-element base rule regardless of source order. */
a[href*="kick.com"],   .acct-btn-kick    { --u-glow: var(--secondary-color); }
a[href*="discord"],    .acct-btn-discord { --u-glow: #7289da; }
a[href*="x.com"]                          { --u-glow: var(--text-primary); }
a[href*="tiktok"]                         { --u-glow: var(--accent-light); }
a[href*="instagram"]                      { --u-glow: #ff2d78; }
a[href*="t.me"]                           { --u-glow: var(--accent-light); }
a[href*="stake.com"]                      { --u-glow: #1fc7d4; }

@media (prefers-reduced-motion: reduce) {
  a::after, button::after {
    animation: none;
  }
}

/* =========================================================
   Welding-spark cursor trail (public/js/spark-trail.js) — was
   404-page-only, now loaded on every page in the site. The script
   itself already no-ops on touch/coarse pointers and
   prefers-reduced-motion, so this positioning rule is all that's
   needed to bring it everywhere else: a full-viewport, click-through
   overlay the canvas draws into.
   ========================================================= */
#spark-trail-canvas {
  position: fixed !important;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 9999 !important;
}

/* =========================================================
   Glass buttons
   Every button and social icon is a pane of tinted glass: the
   page shows through it (backdrop blur), light catches the top
   edge as a bright inner rim, a diagonal sheen runs across the
   face, and the brand colour survives as the tint rather than a
   solid fill. The light that passes through lands on the floor
   below as the blurred caustic in a::after / button::after above.
   ========================================================= */
.btn,
.social-link,
.nav-cta a, a.nav-cta,
.copy-btn,
.acct-login-btn, .acct-btn-primary, .acct-btn-kick {
  /* Tint defaults to neutral; each variant below sets its own. */
  background-color: rgba(255, 255, 255, .06) !important;
  background-image:
    linear-gradient(158deg, rgba(255,255,255,.26) 0%, rgba(255,255,255,.08) 34%, rgba(255,255,255,0) 58%) !important;
  backdrop-filter: blur(14px) saturate(170%);
  -webkit-backdrop-filter: blur(14px) saturate(170%);
  border: 1px solid rgba(255, 255, 255, .22) !important;
  /* Thickness. A block of glass isn't a membrane — the top face
     catches a bright specular, the side walls carry a thinner
     refracted line, and the interior darkens toward the bottom
     where you're looking through more material. Those three
     together are what give it body instead of reading flat. */
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.60),
    inset 0 7px 14px -7px rgba(255,255,255,.40),
    inset 1px 0 0 rgba(255,255,255,.13),
    inset -1px 0 0 rgba(255,255,255,.13),
    inset 0 -12px 20px -12px rgba(0,0,0,.60),
    inset 0 -1px 0 rgba(255,255,255,.10),
    0 8px 24px rgba(0,0,0,.50),
    0 0 24px -6px var(--u-glow);
  color: #fff !important;
  /* the floor caustic sits outside the box — never clip it */
  overflow: visible;
}

/* The tube lighting the block from within: a soft bloom of the
   button's own neon colour sitting in the glass body behind the
   letters. It's a background layer rather than a pseudo-element
   so it can't fight .social-link's grid centring or the sweep
   that giveaway.css already runs on .gw-btn::before. */
@supports (color: color-mix(in srgb, red 50%, transparent)) {
  .btn,
  .social-link,
  .nav-cta a, a.nav-cta,
  .copy-btn,
  .gw-btn,
  .acct-login-btn, .acct-btn-primary, .acct-btn-kick {
    background-image:
      radial-gradient(ellipse 82% 130% at 50% 60%, color-mix(in srgb, var(--u-glow) 32%, transparent) 0%, transparent 70%),
      linear-gradient(158deg, rgba(255,255,255,.28) 0%, rgba(255,255,255,.08) 34%, rgba(255,255,255,0) 58%) !important;
  }
  .btn:hover, .btn:focus-visible,
  .social-link:hover, .social-link:focus-visible,
  .nav-cta a:hover, a.nav-cta:hover,
  .copy-btn:hover, .gw-btn:hover {
    background-image:
      radial-gradient(ellipse 88% 140% at 50% 60%, color-mix(in srgb, var(--u-glow) 46%, transparent) 0%, transparent 72%),
      linear-gradient(158deg, rgba(255,255,255,.34) 0%, rgba(255,255,255,.10) 34%, rgba(255,255,255,0) 58%) !important;
  }
}

/* Brand tint per variant. Kept low-alpha so it reads as coloured
   glass with the page visible through it, not a painted surface. */
.btn-primary,
.acct-login-btn, .acct-btn-primary { background-color: rgba(124, 59, 255, .30) !important; }
.btn-secondary,
.nav-cta a, a.nav-cta,
.acct-btn-kick                     { background-color: rgba(83, 252, 24, .22) !important; }
.btn-light, .copy-btn              { background-color: rgba(255, 255, 255, .07) !important; }

/* Hover: the glass brightens and the rim catches more light. The
   lift itself still comes from the existing .btn:hover transform. */
.btn:hover, .btn:focus-visible,
.social-link:hover, .social-link:focus-visible,
.nav-cta a:hover, a.nav-cta:hover,
.copy-btn:hover, .copy-btn:focus-visible {
  border-color: rgba(255,255,255,.45) !important;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.78),
    inset 0 7px 14px -7px rgba(255,255,255,.55),
    inset 1px 0 0 rgba(255,255,255,.20),
    inset -1px 0 0 rgba(255,255,255,.20),
    inset 0 -12px 20px -12px rgba(0,0,0,.55),
    inset 0 -1px 0 rgba(255,255,255,.14),
    0 12px 30px rgba(0,0,0,.55),
    0 0 40px -6px var(--u-glow);
}

.btn-primary:hover, .acct-login-btn:hover, .acct-btn-primary:hover { background-color: rgba(124, 59, 255, .42) !important; }
.btn-secondary:hover,
.nav-cta a:hover, a.nav-cta:hover  { background-color: rgba(83, 252, 24, .34) !important; }
.btn-light:hover, .copy-btn:hover  { background-color: rgba(255, 255, 255, .13) !important; }
.social-link:hover { color: #fff !important; }

/* Copy-confirmation state stays legible on glass. */
.copy-btn.copied {
  background-color: rgba(83, 252, 24, .34) !important;
  border-color: rgba(83, 252, 24, .55) !important;
  color: #fff !important;
}

/* Backdrop-filter is the one part of this that is genuinely
   expensive. Where the browser can't do it, the tint + rim +
   sheen alone still read as glass, so nothing needs a fallback. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .btn, .social-link, .nav-cta a, a.nav-cta, .copy-btn {
    background-color: rgba(255,255,255,.10) !important;
  }
}

/* =========================================================
   Neon-sign lettering on the buttons
   A glass tube reads as a white-hot filament wrapped in a
   coloured halo, so the text is a tight near-white core with
   the brand colour blooming outward. --neon deliberately
   inherits --u-glow, the same variable driving the caustic on
   the floor — the tube, its bloom, and the light it throws are
   all one colour per button rather than three guesses.
   ========================================================= */
.btn,
.nav-cta a, a.nav-cta,
.copy-btn,
.acct-login-btn, .acct-btn-primary, .acct-btn-kick {
  --neon: var(--u-glow, var(--primary-light));
  /* A lit tube is a white-hot filament you can't quite look at,
     wrapped in progressively wider, dimmer haloes of its own
     colour. The two tight white stops are the filament; the four
     coloured ones are the bloom through the glass. */
  text-shadow:
    0 0 1px #fff,
    0 0 4px rgba(255,255,255,.9),
    0 0 9px var(--neon),
    0 0 20px var(--neon),
    0 0 38px var(--neon),
    0 0 66px var(--neon);
  letter-spacing: .05em;
  transition:
    text-shadow .25s var(--ease),
    background-color .2s var(--ease),
    border-color .2s var(--ease),
    box-shadow .25s var(--ease),
    transform .18s var(--ease);
}

.btn:hover, .btn:focus-visible,
.nav-cta a:hover, a.nav-cta:hover,
.copy-btn:hover, .copy-btn:focus-visible,
.acct-login-btn:hover, .acct-btn-primary:hover, .acct-btn-kick:hover {
  text-shadow:
    0 0 1px #fff,
    0 0 5px #fff,
    0 0 12px var(--neon),
    0 0 28px var(--neon),
    0 0 54px var(--neon),
    0 0 90px var(--neon);
}
.social-link:hover svg { filter: drop-shadow(0 0 11px var(--u-glow)); }

/* A neon tube that never flickers is a still image, but this is
   behind every button on the page — keep it to a slow, shallow
   breath so it stays alive without pulling focus, and drop it
   entirely for anyone who asked for less motion. */
@media (prefers-reduced-motion: reduce) {
  a::after, button::after { animation: none; }
}

/* Square glass tiles rather than pills. 12px matches the radius the
   social icons already use, so every pane of glass on the site —
   button, CTA, icon — shares one corner. */
.btn,
.nav-cta a, a.nav-cta,
.copy-btn,
.acct-login-btn, .acct-btn-primary, .acct-btn-kick {
  border-radius: 12px !important;
}

/* The giveaway portal's buttons are styled by giveaway.css, which
   loads before this file — they'd otherwise be the one set of
   buttons on the site still wearing the old solid-fill look. */
.gw-btn {
  background-color: rgba(124, 59, 255, .30) !important;
  background-image:
    linear-gradient(158deg, rgba(255,255,255,.26) 0%, rgba(255,255,255,.08) 34%, rgba(255,255,255,0) 58%) !important;
  backdrop-filter: blur(14px) saturate(170%);
  -webkit-backdrop-filter: blur(14px) saturate(170%);
  border: 1px solid rgba(255,255,255,.20) !important;
  border-radius: 12px !important;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.60),
    inset 0 7px 14px -7px rgba(255,255,255,.40),
    inset 1px 0 0 rgba(255,255,255,.13),
    inset -1px 0 0 rgba(255,255,255,.13),
    inset 0 -12px 20px -12px rgba(0,0,0,.60),
    inset 0 -1px 0 rgba(255,255,255,.10),
    0 8px 24px rgba(0,0,0,.50),
    0 0 24px -6px var(--u-glow);
  color: #fff !important;
  --neon: var(--u-glow, var(--primary-light));
  text-shadow:
    0 0 1px #fff,
    0 0 4px rgba(255,255,255,.9),
    0 0 9px var(--neon),
    0 0 20px var(--neon),
    0 0 38px var(--neon),
    0 0 66px var(--neon);
}
.gw-btn:hover {
  background-color: rgba(124, 59, 255, .42) !important;
  border-color: rgba(255,255,255,.42) !important;
  text-shadow:
    0 0 1px #fff,
    0 0 5px #fff,
    0 0 12px var(--neon),
    0 0 28px var(--neon),
    0 0 54px var(--neon),
    0 0 90px var(--neon);
}

/* The wide secondary bloom only where there's actually a block of
   glass for the light to refract through. blur() softens the
   caustic itself; drop-shadow() then spreads that already-soft
   shape outward following its alpha, so the spill comes off the
   light's real silhouette rather than a rectangle — a tight core
   inside a wide dim halo, which is what a solid block throws.
   Deliberately not applied to plain text links: it's a second
   filter pass per element, and across a nav and a footer full of
   links that's real GPU cost for a effect that only reads on the
   glass. Text links keep the single blur. */
.btn::after,
.social-link::after,
.nav-cta a::after, a.nav-cta::after,
.copy-btn::after,
.gw-btn::after {
  filter: blur(5px) drop-shadow(0 3px 12px var(--u-glow));
}

/* =========================================================
   Neon lettering standing on a mirror floor — text links
   A glass button is an object with a light inside it; a bare
   text link is just the tube itself. So these get the same
   filament-and-bloom lettering, then an actual mirrored copy
   of the letters below — the real thing flipped and fading,
   which is what a sign standing on polished floor looks like,
   rather than the abstract caustic the glass blocks throw.

   -webkit-box-reflect is Chromium/WebKit only. Firefox renders
   the neon lettering with no reflection, i.e. it degrades to
   the look this replaced rather than to something broken.
   ========================================================= */
.nav-menu > li > a,
.submenu a,
.footer-links a,
.footer-bottom a {
  --neon: var(--u-glow, var(--primary-light));
  color: #fff;
  text-shadow:
    0 0 1px #fff,
    0 0 5px var(--neon),
    0 0 13px var(--neon),
    0 0 26px var(--neon);
  -webkit-box-reflect: below 1px linear-gradient(transparent 48%, rgba(255,255,255,.38));
}

.nav-menu > li > a:hover,
.nav-menu > li > a.active,
.submenu a:hover,
.footer-links a:hover,
.footer-bottom a:hover {
  color: #fff;
  text-shadow:
    0 0 1px #fff,
    0 0 7px var(--neon),
    0 0 18px var(--neon),
    0 0 38px var(--neon),
    0 0 64px var(--neon);
}

/* The reflection replaces the caustic on these — running both
   would mean the blurred pool got mirrored too, which reads as
   a smear sitting under the letters instead of a reflection.
   The ▾ caret rule on .has-submenu is more specific than this
   and deliberately still wins, so Stake keeps its arrow. */
.nav-menu > li > a::after,
.submenu a::after,
.footer-links a::after,
.footer-bottom a::after {
  content: none;
}

/* Reflections need floor to stand on — the old .5rem let each
   one land on the link beneath it. */
.footer-links li { margin-bottom: 1.05rem; }

/* =========================================================
   Footer: neon trademark line + neon-tube social glyphs
   ========================================================= */

/* The whole credit line is one neon sign, not muted grey text
   with a single lit word in it. The reflection moves from the
   okie.digital link up to the paragraph so the entire line
   stands on the floor together — one word reflecting mid-
   sentence read like a rendering bug rather than a sign. */
.footer-bottom {
  color: #fff;
  text-shadow:
    0 0 1px #fff,
    0 0 5px var(--primary-light),
    0 0 13px var(--primary-light),
    0 0 26px var(--primary-light);
}
.footer-bottom p {
  display: inline-block;
  -webkit-box-reflect: below 2px linear-gradient(transparent 50%, rgba(255,255,255,.32));
}
.footer-bottom a {
  color: #fff;
  -webkit-box-reflect: unset;  /* not "none": Chrome rejects that keyword for this legacy property and keeps the inherited reflection */
}
.footer-bottom a:hover {
  text-shadow:
    0 0 1px #fff,
    0 0 7px var(--primary-light),
    0 0 18px var(--primary-light),
    0 0 38px var(--primary-light);
}
.social-link:hover svg {
  filter:
    drop-shadow(0 0 1px #fff)
    drop-shadow(0 0 5px #fff)
    drop-shadow(0 0 13px var(--u-glow))
    drop-shadow(0 0 26px var(--u-glow))
    drop-shadow(0 0 44px var(--u-glow));
}

/* Section headings sit in the same light. */
.footer-column h3 {
  color: #fff;
  text-shadow: 0 0 1px #fff, 0 0 8px var(--primary-light), 0 0 20px var(--primary-light);
}

/* =========================================================
   The glass blocks stand on a mirror floor
   An actual flipped copy of the block — glass, tint, neon and
   all — rather than a painted approximation of one.

   This replaces the caustic on these elements rather than
   joining it. The ::after wash is painted *below* the button,
   so a reflection would mirror it back upward across the
   button's own lower half as a bright smear. The block's own
   soft coloured shadow does survive into the reflection, so
   light still pools where the glass meets the floor — which
   is what you'd actually see under a lit object on a mirror.

   Chromium/WebKit only; Firefox keeps the glass and neon and
   simply stands on nothing, which is a clean degrade.
   ========================================================= */
.btn,
.social-link,
.gw-btn {
  -webkit-box-reflect: below 3px linear-gradient(transparent 54%, rgba(255,255,255,.32));
}

.btn::after,
.social-link::after,
.gw-btn::after {
  content: none;
}

/* Reflections need clearance, or they land on whatever sits
   under the row. */
.hero-buttons, .band-actions { margin-bottom: 1.6rem; }.social-link {
  width: 46px !important;
  height: 46px !important;
  border-radius: 12px;
  display: grid !important;
  place-items: center !important;
  background: var(--surface-solid);
  border: 1px solid var(--line);
  color: rgba(255,255,255,.92) !important;
  transition: transform .18s var(--ease), color .2s, border-color .2s, box-shadow .2s;
}

/* =========================================================
   Service cards are glass blocks too
   ========================================================= */
.service-card {
  --neon: var(--u-glow, var(--primary-light));
  background-color: rgba(124, 59, 255, .16) !important;
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  border: 1px solid rgba(255,255,255,.18) !important;
  border-radius: 12px !important;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.50),
    inset 0 7px 14px -7px rgba(255,255,255,.32),
    inset 1px 0 0 rgba(255,255,255,.10),
    inset -1px 0 0 rgba(255,255,255,.10),
    inset 0 -14px 24px -14px rgba(0,0,0,.60),
    0 8px 24px rgba(0,0,0,.45),
    0 0 26px -8px var(--u-glow);
}
.service-card:hover {
  background-color: rgba(124, 59, 255, .26) !important;
  border-color: rgba(255,255,255,.40) !important;
}
.service-card h3 {
  color: #fff;
  text-shadow:
    0 0 1px #fff,
    0 0 5px var(--neon),
    0 0 14px var(--neon),
    0 0 28px var(--neon);
}
.service-card .service-icon {
  filter: drop-shadow(0 0 8px var(--neon)) drop-shadow(0 0 18px var(--neon));
}
@supports (color: color-mix(in srgb, red 50%, transparent)) {
  .service-card {
    background-image:
      radial-gradient(ellipse 82% 120% at 50% 62%, color-mix(in srgb, var(--u-glow) 24%, transparent) 0%, transparent 72%),
      linear-gradient(158deg, rgba(255,255,255,.22) 0%, rgba(255,255,255,.06) 34%, rgba(255,255,255,0) 58%) !important;
  }
}

/* =========================================================
   Neon strike — clicking fires the tube
   A real neon sign doesn't come on cleanly: the starter arcs,
   the tube half-lights, drops out, catches again, and only then
   settles brighter than it began. That's what these keyframes
   are — failed strikes bunched at the start, the gaps widening
   as it takes, then steady at full brightness.
   ========================================================= */
@keyframes neonStrike {
  0%   { color: rgba(255,255,255,.22); text-shadow: 0 0 2px rgba(255,255,255,.18); }
  5%   { color: #fff;                  text-shadow: 0 0 1px #fff, 0 0 6px var(--neon), 0 0 16px var(--neon); }
  8%   { color: rgba(255,255,255,.20); text-shadow: 0 0 2px rgba(255,255,255,.15); }
  13%  { color: #fff;                  text-shadow: 0 0 1px #fff, 0 0 7px var(--neon), 0 0 18px var(--neon); }
  17%  { color: rgba(255,255,255,.26); text-shadow: 0 0 2px rgba(255,255,255,.18); }
  24%  { color: #fff;                  text-shadow: 0 0 1px #fff, 0 0 8px var(--neon), 0 0 22px var(--neon); }
  29%  { color: rgba(255,255,255,.34); text-shadow: 0 0 3px rgba(255,255,255,.25); }
  38%  { color: #fff;                  text-shadow: 0 0 1px #fff, 0 0 9px var(--neon), 0 0 26px var(--neon), 0 0 44px var(--neon); }
  45%  { color: rgba(255,255,255,.55); text-shadow: 0 0 3px rgba(255,255,255,.4), 0 0 10px var(--neon); }
  56%  { color: #fff;                  text-shadow: 0 0 1px #fff, 0 0 10px var(--neon), 0 0 30px var(--neon), 0 0 56px var(--neon); }
  64%  { color: rgba(255,255,255,.78); text-shadow: 0 0 2px #fff, 0 0 8px var(--neon), 0 0 20px var(--neon); }
  100% { color: #fff;                  text-shadow: 0 0 1px #fff, 0 0 5px #fff, 0 0 13px var(--neon), 0 0 30px var(--neon), 0 0 58px var(--neon), 0 0 95px var(--neon); }
}

/* The glyph is the tube on an icon tile, so it strikes instead
   of the (nonexistent) label. */
@keyframes neonStrikeGlyph {
  0%   { opacity: .2; }
  5%   { opacity: 1; }
  8%   { opacity: .18; }
  13%  { opacity: 1; }
  17%  { opacity: .25; }
  24%  { opacity: 1; }
  29%  { opacity: .35; }
  38%  { opacity: 1; }
  45%  { opacity: .55; }
  56%  { opacity: 1; }
  64%  { opacity: .8; }
  100% { opacity: 1; }
}

/* The floor light comes up with the tube — it's the same lamp. */
@keyframes neonStrikeFloor {
  0%   { opacity: .06; }
  5%   { opacity: .5; }
  8%   { opacity: .05; }
  13%  { opacity: .5; }
  17%  { opacity: .08; }
  24%  { opacity: .55; }
  29%  { opacity: .12; }
  38%  { opacity: .6; }
  45%  { opacity: .25; }
  56%  { opacity: .7; }
  64%  { opacity: .4; }
  100% { opacity: .78; }
}

.neon-firing { animation: neonStrike .95s steps(1, end) 1 both; }
.neon-firing svg { animation: neonStrikeGlyph .95s steps(1, end) 1 both; }
.neon-firing::after { animation: neonStrikeFloor .95s steps(1, end) 1 both !important; }

@media (prefers-reduced-motion: reduce) {
  .neon-firing,
  .neon-firing svg,
  .neon-firing::after { animation: none !important; }
}

/* =========================================================
   Hover brightness parity with the social glyphs
   Stacked drop-shadows compound — each filter re-blurs the
   previous result — while stacked text-shadows all draw from
   the same source alpha and don't. So matching the icons'
   intensity in text takes more layers, and a white core that
   bleeds wider before the colour takes over, rather than just
   larger radii on the coloured ones.
   ========================================================= */
.btn:hover, .btn:focus-visible,
.gw-btn:hover,
.service-card:hover h3,
.nav-cta a:hover, a.nav-cta:hover,
.copy-btn:hover, .copy-btn:focus-visible,
.acct-login-btn:hover, .acct-btn-primary:hover, .acct-btn-kick:hover,
.nav-menu > li > a:hover,
.nav-menu > li > a.active,
.submenu a:hover,
.footer-links a:hover,
.footer-bottom a:hover {
  color: #fff;
  text-shadow:
    0 0 1px #fff,
    0 0 4px #fff,
    0 0 9px #fff,
    0 0 16px var(--neon),
    0 0 30px var(--neon),
    0 0 52px var(--neon),
    0 0 84px var(--neon);
}

/* linear, not steps: the gaps between the early keyframes are
   ~30ms, so those read as instant snaps anyway, while the long
   run to 100% becomes a smooth ramp — which is how a tube that
   has finally caught actually settles. steps() made that last
   stage jump, which looked like a dropped frame. */
.neon-firing { animation: neonStrike .95s linear 1 both; }
.neon-firing svg { animation: neonStrikeGlyph .95s linear 1 both; }
.neon-firing::after { animation: neonStrikeFloor .95s linear 1 both !important; }

/* The big blocks are big tubes — more gas to excite, so they
   fight it longer: more failed strikes, later, before taking. */
@keyframes neonStrikeHard {
  0%   { color: rgba(255,255,255,.16); text-shadow: 0 0 2px rgba(255,255,255,.14); }
  3%   { color: #fff;                  text-shadow: 0 0 1px #fff, 0 0 6px var(--neon); }
  5%   { color: rgba(255,255,255,.14); text-shadow: 0 0 2px rgba(255,255,255,.12); }
  9%   { color: rgba(255,255,255,.9);  text-shadow: 0 0 1px #fff, 0 0 7px var(--neon), 0 0 14px var(--neon); }
  11%  { color: rgba(255,255,255,.13); text-shadow: 0 0 2px rgba(255,255,255,.12); }
  18%  { color: #fff;                  text-shadow: 0 0 1px #fff, 0 0 8px var(--neon), 0 0 18px var(--neon); }
  21%  { color: rgba(255,255,255,.18); text-shadow: 0 0 2px rgba(255,255,255,.15); }
  27%  { color: rgba(255,255,255,.85); text-shadow: 0 0 1px #fff, 0 0 8px var(--neon), 0 0 20px var(--neon); }
  31%  { color: rgba(255,255,255,.2);  text-shadow: 0 0 2px rgba(255,255,255,.16); }
  40%  { color: #fff;                  text-shadow: 0 0 1px #fff, 0 0 9px var(--neon), 0 0 24px var(--neon), 0 0 40px var(--neon); }
  45%  { color: rgba(255,255,255,.3);  text-shadow: 0 0 3px rgba(255,255,255,.22); }
  54%  { color: #fff;                  text-shadow: 0 0 1px #fff, 0 0 10px var(--neon), 0 0 28px var(--neon), 0 0 48px var(--neon); }
  60%  { color: rgba(255,255,255,.5);  text-shadow: 0 0 3px rgba(255,255,255,.35), 0 0 12px var(--neon); }
  70%  { color: rgba(255,255,255,.92); text-shadow: 0 0 2px #fff, 0 0 12px var(--neon), 0 0 32px var(--neon), 0 0 56px var(--neon); }
  78%  { color: rgba(255,255,255,.72); text-shadow: 0 0 2px #fff, 0 0 10px var(--neon), 0 0 24px var(--neon); }
  100% { color: #fff;                  text-shadow: 0 0 1px #fff, 0 0 4px #fff, 0 0 9px #fff, 0 0 16px var(--neon), 0 0 30px var(--neon), 0 0 52px var(--neon), 0 0 84px var(--neon); }
}

.btn.neon-firing,
.gw-btn.neon-firing,
.service-card.neon-firing h3 {
  animation: neonStrikeHard 1.7s linear 1 both;
}
.btn.neon-firing::after,
.gw-btn.neon-firing::after {
  animation: neonStrikeFloor 1.7s linear 1 both !important;
}

@media (prefers-reduced-motion: reduce) {
  .btn.neon-firing,
  .gw-btn.neon-firing,
  .service-card.neon-firing h3,
  .btn.neon-firing::after,
  .gw-btn.neon-firing::after { animation: none !important; }
}

/* =========================================================
   Fix: glare under the small footer links
   At .92rem the glow around each letter is wide relative to
   the letter itself, so mirroring it at .38 opacity merged the
   separate reflected glyphs into one bright smear — glare
   rather than a reflection. The letters keep their brightness;
   only the mirrored copy is pulled back, and it now fades out
   by ~30% of its height so the bloom never has room to pool.
   ========================================================= */
.footer-links a {
  -webkit-box-reflect: below 0 linear-gradient(transparent 70%, rgba(255,255,255,.15));
}

/* =========================================================
   One neon, everywhere — the footer letter links are the
   reference for both states, so both are defined once here
   and every lit thing on the site points at them.

   --neon-off / --neon-on hold the whole shadow list rather
   than a colour, so the pair is written once and each element
   still resolves --neon to its own platform colour. Previously
   each surface carried its own hand-tuned stack, which is how
   the buttons and the glyphs drifted to different brightnesses
   from the letters in the first place.
   ========================================================= */
.btn,
.gw-btn,
.service-card h3,
.nav-cta a, a.nav-cta,
.copy-btn,
.acct-login-btn, .acct-btn-primary, .acct-btn-kick,
.nav-menu > li > a,
.submenu a,
.footer-links a,
.footer-bottom,
.footer-bottom a,
.social-link {
  --neon: var(--u-glow, var(--primary-light));
  --neon-off:
    0 0 1px #fff,
    0 0 5px var(--neon),
    0 0 13px var(--neon),
    0 0 26px var(--neon);
  --neon-on:
    0 0 1px #fff,
    0 0 4px #fff,
    0 0 9px #fff,
    0 0 16px var(--neon),
    0 0 30px var(--neon),
    0 0 52px var(--neon),
    0 0 84px var(--neon);
}

.btn,
.gw-btn,
.service-card h3,
.nav-cta a, a.nav-cta,
.copy-btn,
.acct-login-btn, .acct-btn-primary, .acct-btn-kick,
.nav-menu > li > a,
.submenu a,
.footer-links a,
.footer-bottom,
.footer-bottom a {
  color: #fff;
  text-shadow: var(--neon-off);
  transition: text-shadow .28s var(--ease), color .28s var(--ease);
}

.btn:hover, .btn:focus-visible,
.gw-btn:hover, .gw-btn:focus-visible,
.service-card:hover h3, .service-card:focus-visible h3,
.nav-cta a:hover, a.nav-cta:hover,
.copy-btn:hover, .copy-btn:focus-visible,
.acct-login-btn:hover, .acct-btn-primary:hover, .acct-btn-kick:hover,
.nav-menu > li > a:hover, .nav-menu > li > a:focus-visible,
.nav-menu > li > a.active,
.submenu a:hover, .submenu a:focus-visible,
.footer-links a:hover, .footer-links a:focus-visible,
.footer-bottom a:hover, .footer-bottom a:focus-visible {
  text-shadow: var(--neon-on);
}.social-link svg {
  width: 20px;
  height: 20px;
  filter: drop-shadow(0 0 1px #fff)
    drop-shadow(0 0 5px var(--u-glow))
    drop-shadow(0 0 13px var(--u-glow));
  transition: filter .28s var(--ease);
  color: #fff;
}
.social-link:hover svg,
.social-link:focus-visible svg {
  filter:
    drop-shadow(0 0 1px #fff)
    drop-shadow(0 0 4px #fff)
    drop-shadow(0 0 9px #fff)
    drop-shadow(0 0 16px var(--u-glow))
    drop-shadow(0 0 30px var(--u-glow));
}

/* =========================================================
   Social cards (socials.html) — glass block, neon inside
   The platform colour already resolves per card because the
   --u-glow rules key off the href, so these only need the
   glass shell, the lit label, and the icon tile treated as a
   small pane of its own with the glyph as the tube.
   ========================================================= */
.social-card {
  --neon: var(--u-glow, var(--primary-light));
  background-color: rgba(255, 255, 255, .06) !important;
  backdrop-filter: blur(14px) saturate(170%);
  -webkit-backdrop-filter: blur(14px) saturate(170%);
  border: 1px solid rgba(255,255,255,.20) !important;
  border-radius: 12px !important;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.60),
    inset 0 7px 14px -7px rgba(255,255,255,.38),
    inset 1px 0 0 rgba(255,255,255,.12),
    inset -1px 0 0 rgba(255,255,255,.12),
    inset 0 -14px 24px -14px rgba(0,0,0,.60),
    inset 0 -1px 0 rgba(255,255,255,.10),
    0 8px 24px rgba(0,0,0,.48),
    0 0 26px -8px var(--u-glow);
  overflow: visible;
  -webkit-box-reflect: below 3px linear-gradient(transparent 58%, rgba(255,255,255,.26));
}
.social-card::after { content: none; }

.social-card:hover {
  border-color: rgba(255,255,255,.45) !important;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.78),
    inset 0 7px 14px -7px rgba(255,255,255,.55),
    inset 1px 0 0 rgba(255,255,255,.20),
    inset -1px 0 0 rgba(255,255,255,.20),
    inset 0 -14px 24px -14px rgba(0,0,0,.55),
    inset 0 -1px 0 rgba(255,255,255,.14),
    0 12px 30px rgba(0,0,0,.55),
    0 0 42px -8px var(--u-glow);
}

@supports (color: color-mix(in srgb, red 50%, transparent)) {
  .social-card {
    background-image:
      radial-gradient(ellipse 82% 130% at 50% 60%, color-mix(in srgb, var(--u-glow) 26%, transparent) 0%, transparent 72%),
      linear-gradient(158deg, rgba(255,255,255,.26) 0%, rgba(255,255,255,.08) 34%, rgba(255,255,255,0) 58%) !important;
  }
  .social-card:hover {
    background-image:
      radial-gradient(ellipse 88% 140% at 50% 60%, color-mix(in srgb, var(--u-glow) 40%, transparent) 0%, transparent 74%),
      linear-gradient(158deg, rgba(255,255,255,.34) 0%, rgba(255,255,255,.10) 34%, rgba(255,255,255,0) 58%) !important;
  }
}

/* Platform name is the lit label; the handle underneath stays
   unlit so the card still has a quiet line to read. */
.social-card .txt b {
  color: #fff;
  text-shadow: var(--neon-off);
  transition: text-shadow .28s var(--ease);
}
.social-card:hover .txt b { text-shadow: var(--neon-on); }
.social-card .txt span { color: var(--text-secondary); text-shadow: none; }

/* The icon tile is its own small pane with the glyph as tube. */
.social-card .ico {
  background: rgba(255,255,255,.07) !important;
  border: 1px solid rgba(255,255,255,.20) !important;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.50),
    inset 0 -8px 14px -8px rgba(0,0,0,.55),
    0 0 20px -8px var(--u-glow);
}
.social-card .ico svg {
  color: #fff;
  filter:
    drop-shadow(0 0 1px #fff)
    drop-shadow(0 0 5px var(--u-glow))
    drop-shadow(0 0 13px var(--u-glow));
  transition: filter .28s var(--ease);
}
.social-card:hover .ico svg {
  filter:
    drop-shadow(0 0 1px #fff)
    drop-shadow(0 0 4px #fff)
    drop-shadow(0 0 9px #fff)
    drop-shadow(0 0 16px var(--u-glow))
    drop-shadow(0 0 30px var(--u-glow));
}

/* Social cards are big blocks, so they strike hard like the
   buttons — the label is what lights, not the card. */
.social-card.neon-firing .txt b {
  animation: neonStrikeHard 1.7s linear 1 both;
}
.social-card.neon-firing .ico svg {
  animation: neonStrikeGlyph 1.7s linear 1 both;
}
@media (prefers-reduced-motion: reduce) {
  .social-card.neon-firing .txt b,
  .social-card.neon-firing .ico svg { animation: none !important; }
}

/* =========================================================
   Fix: hard line across the bottom of the service cards
   The caustic opens with a near-white core only a few pixels
   deep — at button width that reads as light touching down,
   but stretched across a 200px+ card it resolves into a
   straight bright rule sitting on the card's bottom edge.
   These are big blocks like the buttons, so they get the same
   answer the buttons got: a real mirrored copy instead of a
   painted strip, which has no edge to go hard.
   ========================================================= */
.service-card {
  -webkit-box-reflect: below 3px linear-gradient(transparent 58%, rgba(255,255,255,.26));
}
.service-card::after { content: none; }

/* Centre the icon + label group in each social card. The card
   is a flex row that was packed to the start, so the content
   sat against the left edge with all the slack on the right. */
.social-card { justify-content: center; }
.social-card .txt { text-align: center; }

/* =========================================================
   Fix: smear under the header emblem
   .logo is an <a>, so it inherited the floor caustic every
   link gets — but the emblem isn't a lit control sitting on a
   surface, it's a mark in the header bar, and a pool of light
   under it just read as a smudge. It keeps the drop-shadow
   halo it already had, which is the glow it's meant to have.
   ========================================================= */
.logo::after { content: none; }
.logo { -webkit-box-reflect: unset;  /* not "none": Chrome rejects that keyword for this legacy property and keeps the inherited reflection */ }

/* =========================================================
   Fix: ghost boxes under the buttons and cards
   A mirrored glass block reflects its 1px border too, so the
   reflection resolved into a second hard-edged rectangle
   sitting under each control — a duplicate box, not light.
   Reflections are dropped here and the floor light goes back
   to being light: a soft wash with no white core, so it can't
   resolve into the hard rule that the earlier version drew
   across the wide cards either. One mechanism, no edges.
   ========================================================= */
.btn,
.gw-btn,
.social-link,
.social-card,
.service-card {
  -webkit-box-reflect: unset;  /* not "none": Chrome rejects that keyword for this legacy property and keeps the inherited reflection */
}

.btn::after,
.gw-btn::after,
.social-link::after,
.social-card::after,
.service-card::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 100%;
  width: 118%;
  height: 40px;
  transform: translateX(-50%);
  transform-origin: 50% 0%;
  /* No near-white stop anywhere — that was the part that went
     hard at width. Colour straight from the contact edge out. */
  background:
    linear-gradient(to bottom, var(--u-glow) 0%, transparent 44%),
    radial-gradient(ellipse 68% 100% at 50% 0%, var(--u-glow) 0%, transparent 76%);
  -webkit-mask-image: radial-gradient(ellipse 56% 100% at 50% 0%, #000 8%, transparent 80%);
  mask-image: radial-gradient(ellipse 56% 100% at 50% 0%, #000 8%, transparent 80%);
  filter: blur(7px);
  opacity: .55;
  pointer-events: none;
  animation: uGlowBreath 2.8s ease-in-out infinite;
  transition: opacity .25s var(--ease), transform .25s var(--ease);
}

.btn:hover::after, .btn:focus-visible::after,
.gw-btn:hover::after,
.social-link:hover::after, .social-link:focus-visible::after,
.social-card:hover::after, .social-card:focus-visible::after,
.service-card:hover::after, .service-card:focus-visible::after {
  opacity: .85;
  transform: translateX(-50%) scaleY(1.2);
}

/* Structure: one button size, one alignment. The rows were
   sized by their own text, so a three-button row stepped in
   width across the row. */
.btn {
  min-width: 190px;
  min-height: 54px;
  padding: .85rem 1.5rem;
  flex: 0 0 auto;
}
.hero-buttons, .band-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: stretch;
}.socials-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--spacing-sm);
  row-gap: var(--spacing-md);
}.social-links {
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
  row-gap: 1rem;
}

/* =========================================================
   Controls shouldn't behave like text
   The cursor was already pointer on all of these; what made
   them feel like a chat box is that their labels were still
   selectable, so a click-drag (or a double-click, or an
   impatient double-tap) painted the label with the selection
   highlight. Body copy stays selectable — only things you
   press are opted out.
   ========================================================= */
.btn,
.gw-btn,
.nav-menu a,
.nav-menu button,
.submenu a,
.footer-links a,
.social-link,
.social-card,
.service-card,
.nav-cta a, a.nav-cta,
.copy-btn,
.logo,
.hamburger,
.submenu-toggle,
.acct-login-btn, .acct-btn-primary, .acct-btn-kick, .acct-chip {
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

/* The Stake code itself is the one "button-adjacent" thing that
   must stay selectable — people copy it by hand. */
.code-box .code {
  -webkit-user-select: all;
  user-select: all;
  cursor: text;
}

/* =========================================================
   Mobile: shed the expensive compositing
   The homepage runs ~32 backdrop-filtered surfaces and ~43
   blurred pseudo-elements, all GPU-bound. That's fine on a
   desktop and punishing on a mid-range phone, where it shows
   up as scroll jank rather than as a slow load. The glass
   reads convincingly from its tint, rim and sheen alone, so
   phones keep the look and drop the per-surface blur.
   ========================================================= */
@media (max-width: 768px) {
  .btn,
  .gw-btn,
  .social-link,
  .social-card,
  .service-card,
  .nav-cta a, a.nav-cta,
  .copy-btn {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }

  /* Slightly more opaque to compensate for losing the blur,
     so the glass doesn't go flat and washed out. */
  .btn-primary, .acct-login-btn, .acct-btn-primary { background-color: rgba(124, 59, 255, .42) !important; }
  .btn-secondary, .nav-cta a, a.nav-cta, .acct-btn-kick { background-color: rgba(83, 252, 24, .30) !important; }
  .btn-light, .copy-btn { background-color: rgba(255, 255, 255, .12) !important; }
  .social-card { background-color: rgba(255, 255, 255, .10) !important; }
  .service-card { background-color: rgba(124, 59, 255, .26) !important; }

  /* The floor wash is a blur per control; one is fine, forty
     is not. Keep it on the big controls, drop it elsewhere. */
  .social-link::after { content: none; }
}.logo img {
  height: 30px;
  filter: drop-shadow(0 0 1px #fff)
    drop-shadow(0 0 5px var(--primary-light))
    drop-shadow(0 0 13px var(--primary-light));
  transition: filter .28s var(--ease);
}
.logo:hover img,
.logo:focus-visible img {
  filter:
    drop-shadow(0 0 1px #fff)
    drop-shadow(0 0 4px #fff)
    drop-shadow(0 0 9px #fff)
    drop-shadow(0 0 16px var(--primary-light))
    drop-shadow(0 0 30px var(--primary-light));
}

/* It strikes on click like every other lit control. */
.logo.neon-firing img {
  animation: neonStrikeGlyph .95s linear 1 both;
}
@media (prefers-reduced-motion: reduce) {
  .logo.neon-firing img { animation: none !important; }
}

/* =========================================================
   Intro: clicking throws the light switch
   The splash used to just cross-fade out. Now the click reads
   as flipping the breaker on the room — the tubes stutter,
   catch, fail, catch harder, then flood the frame and blow out
   to reveal the page behind. Same failed-strike rhythm as the
   buttons, scaled up to the whole screen.

   brightness() on the overlay does the work: everything in the
   splash (nebula, emblem, wordmark) is lit by one source, so
   driving them together is what makes it feel like room lights
   rather than an element animating.
   ========================================================= */

/* The flood itself — a violet-white wash that comes up with the
   tubes and carries the last stage, so the reveal is light
   filling the frame rather than the splash simply fading. */


/* Anyone who asked for less motion gets the plain fade the
   splash always had — .done is still what that path uses. */
@media (prefers-reduced-motion: reduce) {}

/* =========================================================
   APP SHELL — persistent left rail + top bar
   Structure only: a collapsible icon sidebar, a status/profile
   top bar, and a card-grid body. The nav lists 3adooli's own
   destinations; no feature set is carried over from elsewhere.
   ========================================================= */
:root {
  --rail-w: 236px;
  --rail-w-collapsed: 72px;
  --topbar-h: 64px;
}

body.app-body { padding-left: var(--rail-w); transition: padding-left .28s var(--ease); }
body.app-body.rail-collapsed { padding-left: var(--rail-w-collapsed); }

/* ---- Left rail ---- */
.rail {
  position: fixed; inset: 0 auto 0 0; width: var(--rail-w); z-index: 1200;
  display: flex; flex-direction: column;
  background: rgba(9, 6, 18, .92);
  backdrop-filter: blur(16px) saturate(150%);
  -webkit-backdrop-filter: blur(16px) saturate(150%);
  border-right: 1px solid var(--line);
  transition: width .28s var(--ease);
  overflow: hidden;
}
.app-body.rail-collapsed .rail { width: var(--rail-w-collapsed); }

.rail-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: .5rem; padding: 0 .85rem; height: var(--topbar-h); flex: 0 0 auto;
  border-bottom: 1px solid var(--line);
}
.rail-logo { display: inline-flex; align-items: center; gap: .5rem; overflow: hidden; }
.rail-logo img.mark { height: 30px; width: 30px; flex: 0 0 auto; }
.rail-logo img.wordmark { height: 20px; width: auto; opacity: .95; transition: opacity .2s var(--ease); }
.app-body.rail-collapsed .rail-logo img.wordmark { opacity: 0; }

.rail-toggle {
  display: inline-grid; place-items: center; width: 38px; height: 38px; flex: 0 0 auto;
  border-radius: 10px; border: 1px solid var(--line); background: rgba(255,255,255,.05);
  color: var(--text-primary); cursor: pointer;
}
.rail-toggle:hover { border-color: var(--primary-light); }
.rail-toggle svg { width: 18px; height: 18px; }

.rail-nav { list-style: none; margin: 0; padding: .75rem .6rem; display: grid; gap: .25rem; overflow-y: auto; flex: 1 1 auto; }
.rail-nav::-webkit-scrollbar { width: 6px; }
.rail-nav::-webkit-scrollbar-thumb { background: rgba(124,59,255,.35); border-radius: 99px; }

.rail-section {
  font-family: var(--font-heading); font-size: .64rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--text-muted);
  padding: .9rem .75rem .35rem; white-space: nowrap;
  transition: opacity .2s var(--ease);
}
.app-body.rail-collapsed .rail-section { opacity: 0; }

.rail-link {
  display: flex; align-items: center; gap: .8rem;
  padding: .68rem .75rem; border-radius: 11px; white-space: nowrap;
  color: var(--text-secondary); font-weight: 600; font-size: .95rem;
  border: 1px solid transparent;
  transition: background .2s var(--ease), color .2s var(--ease), border-color .2s var(--ease);
}
.rail-link svg { width: 20px; height: 20px; flex: 0 0 auto; }
.rail-link .label { transition: opacity .2s var(--ease); }
.app-body.rail-collapsed .rail-link .label { opacity: 0; }

.rail-link:hover { background: rgba(124,59,255,.14); color: #fff; }
.rail-link.active {
  background: linear-gradient(135deg, var(--primary-color), var(--primary-dark));
  color: #fff; border-color: rgba(255,255,255,.18);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.35), 0 6px 18px rgba(124,59,255,.35);
}

/* Not built yet. Shown so the finished shape of the nav is
   visible, but plainly inert — a link that silently goes
   nowhere is worse than one that admits it is not ready. */
.rail-link.soon { opacity: .45; cursor: default; pointer-events: none; }
.rail-link.soon .tag {
  margin-left: auto; font-size: .58rem; letter-spacing: .12em; text-transform: uppercase;
  padding: .16rem .4rem; border-radius: 5px; border: 1px solid var(--line-strong); color: var(--text-muted);
}
.app-body.rail-collapsed .rail-link.soon .tag { display: none; }

/* ---- Top bar ---- */
.topbar {
  position: sticky; top: 0; z-index: 1100; height: var(--topbar-h);
  display: flex; align-items: center; gap: 1rem; padding: 0 1.1rem;
  background: rgba(9, 6, 18, .82);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}
.topbar-spacer { flex: 1 1 auto; }

.status-pill {
  display: inline-flex; align-items: center; gap: .55rem;
  padding: .5rem .9rem; border-radius: 11px;
  background: rgba(255,255,255,.05); border: 1px solid var(--line);
  font-family: var(--font-heading); font-weight: 700; font-size: .74rem; letter-spacing: .1em;
  color: var(--text-secondary);
}
.status-pill svg { width: 16px; height: 16px; }
.status-pill .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-muted); }
.status-pill.is-live { border-color: rgba(83,252,24,.5); color: #fff; }
.status-pill.is-live .dot { background: var(--secondary-color); box-shadow: 0 0 10px var(--secondary-color); animation: pulse 1.6s infinite; }

.rail-mobile-toggle { display: none; }
.rail-scrim { display: none; }

/* ---- Profile chip + dropdown ---- */
.profile { position: relative; }
.profile-chip {
  display: inline-flex; align-items: center; gap: .6rem;
  padding: .4rem .7rem .4rem .4rem; border-radius: 12px;
  background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.18);
  color: #fff; cursor: pointer; font-family: inherit;
}
.profile-chip:hover { border-color: rgba(255,255,255,.4); }
.profile-chip .avatar {
  width: 34px; height: 34px; border-radius: 50%; flex: 0 0 auto;
  display: grid; place-items: center; font-weight: 800; font-family: var(--font-heading);
  background: linear-gradient(135deg, var(--primary-color), var(--accent-color)); color: #fff;
  background-size: cover; background-position: center;
}
.profile-chip .who { display: grid; text-align: left; line-height: 1.15; }
.profile-chip .who b { font-size: .88rem; }
.profile-chip .who span { font-size: .72rem; color: var(--text-muted); }
.profile-chip .caret { width: 14px; height: 14px; color: var(--text-secondary); }

.profile-menu {
  position: absolute; top: calc(100% + .6rem); right: 0; width: 268px;
  background: rgba(16, 11, 32, .97);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(255,255,255,.16); border-radius: 14px;
  box-shadow: 0 18px 44px rgba(0,0,0,.6);
  padding: 1rem; z-index: 1300;
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity .2s var(--ease), transform .2s var(--ease), visibility .2s;
}
.profile.open .profile-menu { opacity: 1; visibility: visible; transform: none; }

.profile-menu-head { display: grid; justify-items: center; gap: .45rem; text-align: center; padding-bottom: .9rem; }
.profile-menu-head .avatar-lg {
  width: 62px; height: 62px; border-radius: 50%;
  display: grid; place-items: center; font-size: 1.5rem; font-weight: 800; font-family: var(--font-heading);
  background: linear-gradient(135deg, var(--primary-color), var(--accent-color)); color: #fff;
  background-size: cover; background-position: center;
  box-shadow: 0 0 0 3px rgba(124,59,255,.3);
}
.profile-menu-head .name { font-family: var(--font-heading); font-weight: 800; font-size: 1.02rem; color: #fff; }
.profile-menu-head .member-id {
  font-size: .66rem; letter-spacing: .1em; text-transform: uppercase;
  padding: .18rem .5rem; border-radius: 6px;
  background: rgba(124,59,255,.22); border: 1px solid var(--line-strong); color: var(--primary-light);
}

/* Verification progress — driven by real linked-account state,
   not an invented XP number. */
.profile-progress { padding: .2rem 0 .9rem; border-bottom: 1px solid var(--line); }
.profile-progress-row { display: flex; justify-content: space-between; font-size: .74rem; color: var(--text-secondary); margin-bottom: .4rem; }
.profile-progress-track { height: 6px; border-radius: 99px; background: rgba(255,255,255,.08); overflow: hidden; }
.profile-progress-fill {
  height: 100%; width: 0%; border-radius: 99px;
  background: linear-gradient(90deg, var(--primary-color), var(--accent-color));
  box-shadow: 0 0 12px var(--primary-color);
  transition: width .4s var(--ease);
}

.profile-menu-list { list-style: none; margin: .7rem 0 0; padding: 0; display: grid; gap: .15rem; }
.profile-menu-list a, .profile-menu-list button {
  display: flex; align-items: center; gap: .7rem; width: 100%;
  padding: .6rem .65rem; border-radius: 9px; border: 0; background: none;
  color: var(--text-secondary); font-size: .9rem; font-weight: 600; cursor: pointer; text-align: left;
  font-family: inherit;
}
.profile-menu-list a:hover, .profile-menu-list button:hover { background: rgba(124,59,255,.16); color: #fff; }
.profile-menu-list svg { width: 17px; height: 17px; }
.profile-menu-list .danger { color: #ff8a8a; }
.profile-menu-list .danger:hover { background: rgba(255,80,80,.14); color: #ffb3b3; }

/* The rail and top bar are chrome, not content — they sit
   outside the neon/mirror system the page body uses. */
.rail a::after, .rail button::after,
.topbar a::after, .topbar button::after,
.profile-menu a::after, .profile-menu button::after { content: none; }
.rail a, .rail button, .topbar a, .topbar button,
.profile-menu a, .profile-menu button { text-shadow: none; -webkit-box-reflect: unset; }

/* ---- Mobile: rail becomes an off-canvas drawer ---- */
@media (max-width: 900px) {
  body.app-body, body.app-body.rail-collapsed { padding-left: 0; }
  .rail { transform: translateX(-100%); width: var(--rail-w); transition: transform .3s var(--ease); }
  .app-body.rail-open .rail { transform: none; }
  .app-body.rail-collapsed .rail { width: var(--rail-w); }
  .app-body.rail-collapsed .rail-link .label,
  .app-body.rail-collapsed .rail-logo img.wordmark,
  .app-body.rail-collapsed .rail-section { opacity: 1; }
  .rail-toggle { display: none; }
  .rail-mobile-toggle {
    display: inline-grid; place-items: center; width: 40px; height: 40px;
    border-radius: 10px; border: 1px solid var(--line); background: rgba(255,255,255,.05);
    color: #fff; cursor: pointer;
  }
  .rail-mobile-toggle svg { width: 20px; height: 20px; }
  .rail-scrim {
    display: block; position: fixed; inset: 0; z-index: 1150; background: rgba(4,2,10,.65);
    opacity: 0; visibility: hidden; transition: opacity .3s var(--ease), visibility .3s;
  }
  .app-body.rail-open .rail-scrim { opacity: 1; visibility: visible; }
  .profile-chip .who { display: none; }
}

/* =========================================================
   Full-bleed inside the shell
   The hero broke out with 100vw, which was right when the page
   owned the whole viewport. With a fixed rail it isn't: 100vw
   still measures the window, so the image overflowed to the
   right and its centring margin dragged it under the rail.
   --shell-inset is however much width the rail is currently
   taking, so "full width" now means the content area, and it
   follows the rail as it collapses or goes off-canvas.
   ========================================================= */
.app-body { --shell-inset: var(--rail-w); }
.app-body.rail-collapsed { --shell-inset: var(--rail-w-collapsed); }
@media (max-width: 900px) {
  .app-body, .app-body.rail-collapsed { --shell-inset: 0px; }
}

.app-body .hero-featured {
  width: calc(100vw - var(--shell-inset));
  max-width: calc(100vw - var(--shell-inset));
  margin-left: calc(50% - (100vw - var(--shell-inset)) / 2);
  margin-right: calc(50% - (100vw - var(--shell-inset)) / 2);
  transition: width .28s var(--ease), margin .28s var(--ease);
}

/* =========================================================
   Affiliate cards — two offers side by side
   A wide glass panel per platform: wordmark up top, the perks
   as a checked list, one action at the bottom. Two columns on
   desktop, stacked on narrow screens.
   ========================================================= */
.affiliate-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: var(--spacing-md);
  max-width: 940px;
  margin: 0 auto;
}

.affiliate-card {
  --neon: var(--u-glow, var(--primary-light));
  display: flex; flex-direction: column;
  padding: 1.6rem 1.5rem 1.4rem;
  border-radius: 14px;
  background-color: rgba(255, 255, 255, .05);
  background-image: linear-gradient(158deg, rgba(255,255,255,.22) 0%, rgba(255,255,255,.06) 34%, rgba(255,255,255,0) 58%);
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  border: 1px solid rgba(255,255,255,.18);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.55),
    inset 0 7px 14px -7px rgba(255,255,255,.32),
    inset 0 -14px 24px -14px rgba(0,0,0,.6),
    0 8px 24px rgba(0,0,0,.45);
}

.affiliate-head {
  display: grid; place-items: center; gap: .3rem;
  padding-bottom: 1.2rem; margin-bottom: 1.2rem;
  border-bottom: 1px solid var(--line);
  min-height: 92px;
}
.affiliate-head .brand {
  font-family: var(--font-heading); font-weight: 800;
  font-size: clamp(1.5rem, 3.4vw, 2rem); letter-spacing: .01em; color: #fff;
  text-shadow: 0 0 1px #fff, 0 0 6px var(--neon), 0 0 16px var(--neon), 0 0 32px var(--neon);
}
.affiliate-head .brand .suffix { font-size: .5em; opacity: .75; margin-left: .12em; letter-spacing: .06em; }

.affiliate-perks { list-style: none; margin: 0 0 1.4rem; padding: 0; display: grid; gap: .72rem; flex: 1 1 auto; }
.affiliate-perks li {
  display: grid; grid-template-columns: 20px 1fr; gap: .65rem; align-items: start;
  color: var(--text-secondary); font-size: .93rem; line-height: 1.45;
}
.affiliate-perks svg { width: 18px; height: 18px; margin-top: .15rem; color: var(--secondary-color); }

.affiliate-card .btn { width: 100%; }

/* The affiliate offer is a gambling signup — the disclosure sits with
   the action, not only once at the top of the page. */
.affiliate-note {
  margin-top: .85rem; text-align: center;
  font-size: .74rem; color: var(--text-muted); line-height: 1.4;
}

@media (max-width: 700px) {
  .affiliate-grid { grid-template-columns: 1fr; }
}

/* Carried over from styles.css — the one rule admin.html and
   giveaway-history.html still needed from that 162KB sheet, which is
   why the sheet itself is no longer loaded anywhere. */
.text-muted { color: var(--text-muted); }

/* =========================================================
   Tile grid — the browse surface
   Two large tiles, then a three-up row, then the tiles whose
   features are not built yet. Each is art on top, label and
   chevron along the bottom, so a row scans as a set of doors
   rather than a wall of prose.
   ========================================================= */
.tile-grid { display: grid; gap: var(--spacing-md); margin-bottom: var(--spacing-md); }
.tile-grid.cols-2 { grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); }
.tile-grid.cols-3 { grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }

/* Same glass as the buttons, not an approximation of it. The tiles were
   missing three things the buttons have, which is why they read as flat
   panels next to them: the side-wall insets that give the glass edges,
   the coloured rim glow, and overflow:visible so the light they throw
   isn't clipped off at the border. */
.tile {
  --neon: var(--u-glow, var(--primary-light));
  position: relative;
  display: flex; flex-direction: column;
  min-height: 190px;
  border-radius: 14px;
  overflow: visible;
  background-color: rgba(255, 255, 255, .06);
  background-image: linear-gradient(158deg, rgba(255,255,255,.26) 0%, rgba(255,255,255,.08) 34%, rgba(255,255,255,0) 58%);
  backdrop-filter: blur(14px) saturate(170%);
  -webkit-backdrop-filter: blur(14px) saturate(170%);
  border: 1px solid rgba(255,255,255,.22);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.60),
    inset 0 7px 14px -7px rgba(255,255,255,.40),
    inset 1px 0 0 rgba(255,255,255,.13),
    inset -1px 0 0 rgba(255,255,255,.13),
    inset 0 -12px 20px -12px rgba(0,0,0,.60),
    inset 0 -1px 0 rgba(255,255,255,.10),
    0 8px 24px rgba(0,0,0,.50),
    0 0 24px -6px var(--u-glow);
  transition: transform .2s var(--ease), border-color .2s var(--ease), box-shadow .25s var(--ease), background-color .2s var(--ease);
}
.tile:hover {
  transform: translateY(-4px);
  border-color: rgba(255,255,255,.45);
  background-color: rgba(255,255,255,.10);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.78),
    inset 0 7px 14px -7px rgba(255,255,255,.55),
    inset 1px 0 0 rgba(255,255,255,.20),
    inset -1px 0 0 rgba(255,255,255,.20),
    inset 0 -12px 20px -12px rgba(0,0,0,.55),
    inset 0 -1px 0 rgba(255,255,255,.14),
    0 12px 30px rgba(0,0,0,.55),
    0 0 40px -6px var(--u-glow);
}

/* The interior bloom the glass buttons get — the tube lighting the block
   from within. Without it a tile is a tinted pane; with it, it reads lit. */
@supports (color: color-mix(in srgb, red 50%, transparent)) {
  .tile {
    background-image:
      radial-gradient(ellipse 82% 130% at 50% 60%, color-mix(in srgb, var(--u-glow) 30%, transparent) 0%, transparent 70%),
      linear-gradient(158deg, rgba(255,255,255,.26) 0%, rgba(255,255,255,.08) 34%, rgba(255,255,255,0) 58%);
  }
  .tile:hover {
    background-image:
      radial-gradient(ellipse 88% 140% at 50% 60%, color-mix(in srgb, var(--u-glow) 44%, transparent) 0%, transparent 72%),
      linear-gradient(158deg, rgba(255,255,255,.34) 0%, rgba(255,255,255,.10) 34%, rgba(255,255,255,0) 58%);
  }
}

/* Light on the floor, same as every other glass control. This was
   suppressed when the tiles had their own glow baked in; now that they
   use the button treatment they should throw light like one. */
.tile::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 100%;
  width: 118%;
  height: 40px;
  transform: translateX(-50%);
  transform-origin: 50% 0%;
  background:
    linear-gradient(to bottom, var(--u-glow) 0%, transparent 44%),
    radial-gradient(ellipse 68% 100% at 50% 0%, var(--u-glow) 0%, transparent 76%);
  -webkit-mask-image: radial-gradient(ellipse 56% 100% at 50% 0%, #000 8%, transparent 80%);
  mask-image: radial-gradient(ellipse 56% 100% at 50% 0%, #000 8%, transparent 80%);
  filter: blur(7px);
  opacity: .5;
  pointer-events: none;
  animation: uGlowBreath 2.8s ease-in-out infinite;
  transition: opacity .25s var(--ease), transform .25s var(--ease);
}
.tile:hover::after { opacity: .85; transform: translateX(-50%) scaleY(1.2); }

.tile-lg { min-height: 260px; }

/* Art plate. The glow behind the mark is the tile's own colour, so a
   row reads as distinct destinations at a glance rather than a set of
   identical panels. */
.tile-art {
  flex: 1 1 auto;
  display: grid; place-items: center;
  padding: 1.6rem 1rem .6rem;
  position: relative;
}
.tile-art::before {
  content: '';
  position: absolute; inset: 12% 18% 8%;
  background: radial-gradient(ellipse at 50% 45%, var(--neon) 0%, transparent 68%);
  opacity: .16;
  filter: blur(14px);
  pointer-events: none;
}
/* Same stacked drop-shadows the social glyphs use, and the same step up
   on hover — the icon is the lit element in a tile, so it should behave
   like one rather than sit flat. */
.tile-art .glyph {
  font-size: 2.9rem; line-height: 1;
  filter:
    drop-shadow(0 0 1px #fff)
    drop-shadow(0 0 6px var(--neon))
    drop-shadow(0 0 16px var(--neon));
  transition: filter .28s var(--ease);
}
.tile:hover .tile-art .glyph {
  filter:
    drop-shadow(0 0 1px #fff)
    drop-shadow(0 0 5px #fff)
    drop-shadow(0 0 14px var(--neon))
    drop-shadow(0 0 30px var(--neon));
}
.tile-lg .tile-art .glyph { font-size: 3.6rem; }
.tile-art svg {
  width: 46px; height: 46px; color: #fff;
  filter:
    drop-shadow(0 0 1px #fff)
    drop-shadow(0 0 6px var(--neon))
    drop-shadow(0 0 16px var(--neon));
  transition: filter .28s var(--ease);
}

.tile-foot {
  display: flex; align-items: center; justify-content: space-between; gap: .8rem;
  padding: .9rem 1.1rem 1rem;
  border-top: 1px solid rgba(255,255,255,.08);
}
/* Uses the shared --neon-off / --neon-on pair rather than a hand-tuned
   stack, so a tile label is lit to exactly the same brightness as a
   button label. Its own stack was dimmer, which is most of why the
   tiles looked unlit next to the buttons. */
.tile-label {
  --neon-off:
    0 0 1px #fff,
    0 0 5px var(--neon),
    0 0 13px var(--neon),
    0 0 26px var(--neon);
  --neon-on:
    0 0 1px #fff,
    0 0 4px #fff,
    0 0 9px #fff,
    0 0 16px var(--neon),
    0 0 30px var(--neon),
    0 0 52px var(--neon),
    0 0 84px var(--neon);
  font-family: var(--font-heading); font-weight: 800;
  font-size: .95rem; letter-spacing: .07em; text-transform: uppercase; color: #fff;
  text-shadow: var(--neon-off);
  transition: text-shadow .28s var(--ease);
}
.tile:hover .tile-label { text-shadow: var(--neon-on); }
.tile-chevron { width: 18px; height: 18px; color: var(--text-secondary); flex: 0 0 auto; transition: transform .2s var(--ease), color .2s var(--ease); }
.tile:hover .tile-chevron { color: #fff; transform: translateX(3px); }
.tile-sub { padding: 0 1.1rem 1rem; margin-top: -.4rem; color: var(--text-secondary); font-size: .88rem; line-height: 1.4; }

/* Not built yet: legible, obviously inert, and not a link — the same
   rule the rail follows, so nothing on the page promises a destination
   that is not there. */
.tile.soon { opacity: .5; pointer-events: none; min-height: 150px; }
.tile.soon .tile-art .glyph, .tile.soon .tile-art svg { filter: none; opacity: .7; }
.tile.soon .tile-label { text-shadow: none; color: var(--text-secondary); }
.tile.soon .tile-foot .tag {
  font-size: .58rem; letter-spacing: .12em; text-transform: uppercase;
  padding: .18rem .45rem; border-radius: 5px;
  border: 1px solid var(--line-strong); color: var(--text-muted);
}

/* The floor light is defined on .tile::after above — it is deliberately
   NOT suppressed here any more. Tiles are glass controls like the
   buttons, so they throw light like the buttons do. */

@media (max-width: 640px) {
  .tile, .tile-lg { min-height: 160px; }
  .tile-art .glyph, .tile-lg .tile-art .glyph { font-size: 2.4rem; }
  .tile { backdrop-filter: none; -webkit-backdrop-filter: none; background-color: rgba(255,255,255,.09); }
}

/* =========================================================
   Tokens inherited from the retired styles.css
   account.css and giveaway.css were written against these and
   still reference them. When styles.css stopped being loaded,
   every one of these fell through to its initial value — the
   same silent failure that put the OBS overlay in Times New
   Roman. Defined here so theme.css is a complete token set for
   every page that loads it, and scripts/css-vars-check.js keeps
   it that way.
   ========================================================= */
:root {
  --bg-glass-black: rgba(8, 8, 10, 0.85);
  --border-color: #2a2150;
  --error-color: #f87171;
  --radius-sm: 12px;
  --radius-md: 16px;
  --radius-lg: 22px;
  --glass-blur: 14px;
  --glass-sheen: linear-gradient(180deg, rgba(255, 255, 255, 0.14), rgba(255, 255, 255, 0) 40%);
  --glow-green: 0 0 18px rgba(83, 252, 24, 0.6), 0 0 42px rgba(83, 252, 24, 0.35);
}

/* =========================================================
   Reduced motion — shell and tiles
   These were added after the first reduced-motion pass and so
   were never covered by it. Transform-based hover lifts and a
   sliding drawer are exactly the vestibular triggers the
   setting exists for, so movement goes and only colour stays.
   ========================================================= */
@media (prefers-reduced-motion: reduce) {
  .tile { transition: border-color .2s, background-color .2s, box-shadow .2s; }
  .tile:hover { transform: none; }
  .tile-chevron { transition: color .2s; }
  .tile:hover .tile-chevron { transform: none; }

  .rail,
  .app-body,
  .profile-menu { transition: none; }

  .rail-link,
  .social-card,
  .service-card,
  .affiliate-card { transition: background-color .2s, border-color .2s, color .2s; }
  .social-card:hover,
  .service-card:hover { transform: none; }
}

/* =========================================================
   Hero: the whole photograph, uncropped
   It was set to a fixed height with object-fit:cover, which
   fills the box by cutting off whatever doesn't fit — so the
   edges of the room were never visible at any window size.
   Both sources are 16:9 (1672x941 and 900x507), so letting the
   image size itself from its own aspect ratio shows all of it
   and can't letterbox.

   aspect-ratio holds the space before the file decodes, which
   keeps the tiles below from jumping up and then down again as
   it loads — the reason a fixed height was there originally.
   ========================================================= */
.app-body .hero-picture img {
  width: 100%;
  height: auto;
  aspect-ratio: 1672 / 941;
  object-fit: contain;
  object-position: center;
}

/* Provided by the inline palette that giveaway.html used to carry.
   Removing that block (it duplicated theme.css) left giveaway.css
   referencing these with nothing behind them — caught by
   scripts/css-vars-check.js before it shipped. */
:root {
  --bg-void: #08060f;
  --bg-panel: #150f2b;
  --secondary-light: #9bff6e;
}

/* =========================================================
   Connect hub
   Watch Live / Join Discord moved up out of the old CTA band
   at the foot of the page, so the two things most visitors
   came to do sit with the platforms instead of below them.
   ========================================================= */
.connect-actions {
  display: flex; flex-wrap: wrap; gap: 1rem;
  justify-content: center;
  margin: 0 auto var(--spacing-md);
}
.connect-stake { margin-top: var(--spacing-lg); }
.connect-stake .section-title { font-size: clamp(1.4rem, 3vw, 1.9rem); }

/* Stake.us glows red so the two offers are told apart at a glance
   rather than by reading the wordmark. Red rather than black: a glow
   is light, and there is no such thing as black light — a dark "glow"
   on a dark page is just an absence, which is why the alternative
   could not have worked. */
.affiliate-card[data-platform="stake-us"] {
  --u-glow: #ff2f4d;
  --neon: #ff2f4d;
  border-color: rgba(255, 47, 77, .38) !important;
}
.affiliate-card[data-platform="stake-us"]:hover {
  border-color: rgba(255, 47, 77, .70) !important;
}
.affiliate-card[data-platform="stake-us"] .btn {
  background-color: rgba(255, 47, 77, .30) !important;
  --u-glow: #ff2f4d;
}
.affiliate-card[data-platform="stake-us"] .btn:hover {
  background-color: rgba(255, 47, 77, .44) !important;
}
/* Its checkmarks pick up the same red so the card reads as one piece. */
.affiliate-card[data-platform="stake-us"] .affiliate-perks svg { color: #ff2f4d; }

/* Stake.com keeps the site violet, so the pair contrast. */
.affiliate-card[data-platform="stake-com"] { --u-glow: var(--primary-light); --neon: var(--primary-light); }

/* =========================================================
   Intro: graffiti burst out of the wordmark
   Replaces the lights-on flicker. The name holds for a beat,
   then paint blows out of it and the page is underneath.
   Shards are generated in home.js (position, colour, angle and
   spin per piece) — this only describes how one behaves.
   ========================================================= */
.graffiti-layer {
  position: absolute; inset: 0;
  pointer-events: none;
  overflow: visible;
  z-index: 3;
}
.graffiti-bit {
  position: absolute;
  display: block;
  transform: translate(-50%, -50%);
  opacity: 0;
  will-change: transform, opacity;
  animation: graffitiFly .95s cubic-bezier(.16,.84,.34,1) forwards;
  box-shadow: 0 0 10px currentColor;
}

/* Out fast, slowing as it goes, fading only at the end — paint thrown,
   not particles drifting. The 8% stop is what gives it the hard snap
   at the start instead of an ease-in creep. */
@keyframes graffitiFly {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(.3) rotate(0deg); }
  8%   { opacity: 1; transform: translate(-50%, -50%) scale(1.15) rotate(calc(var(--spin) * .12)); }
  70%  { opacity: 1; }
  100% {
    opacity: 0;
    transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(.5) rotate(var(--spin));
  }
}

/* The name itself kicks once as the paint leaves it, then the whole
   splash lifts away. */
@keyframes introKick {
  0%   { transform: scale(1); }
  14%  { transform: scale(1.12); }
  34%  { transform: scale(.97); }
  100% { transform: scale(1.04); }
}
@keyframes introClear {
  0%, 45% { opacity: 1; }
  100%    { opacity: 0; visibility: hidden; }
}

#intro.bursting { animation: introClear 1.35s ease-in forwards; pointer-events: none; }
#intro.bursting .intro-word { animation: introKick .9s cubic-bezier(.34,1.56,.64,1) forwards; }
#intro.bursting .intro-emblem { animation: introKick .9s cubic-bezier(.34,1.56,.64,1) .04s forwards; }
/* The loading bar and hint have done their job by now. */
#intro.bursting .intro-bar,
#intro.bursting .intro-hint { opacity: 0; transition: opacity .25s ease; }

@media (prefers-reduced-motion: reduce) {
  .graffiti-bit { animation: none; display: none; }
  #intro.bursting,
  #intro.bursting .intro-word,
  #intro.bursting .intro-emblem { animation: none; }
}

/* =========================================================
   Rail brand: emblem + wordmark, larger
   ========================================================= */
.rail-head { height: auto; padding: 1rem .85rem; }
.rail-logo { gap: .7rem; }
.rail-logo img.mark { height: 52px; width: 52px; }
.rail-logo img.wordmark { height: 34px; }
.app-body.rail-collapsed .rail-logo img.mark { height: 40px; width: 40px; }

/* =========================================================
   A colour per tile
   Only Watch Live looked lit, and not because its glow was
   stronger — every tile throws light at the same opacity. It
   links to kick.com, so it inherited Kick green, while the rest
   fell back to --primary-light. That violet sits on a violet
   nebula, so their light was there and simply invisible.
   Each destination now gets a colour that separates from the
   background, which also makes the row scannable by colour.
   ========================================================= */
.tile[href*="giveaway"]  { --u-glow: #ff2f4d; --neon: #ff2f4d; }  /* prize red */
.tile[href*="socials"]   { --u-glow: #4bb8ff; --neon: #4bb8ff; }  /* signal blue */
.tile[href*="stake"]     { --u-glow: #ffc53b; --neon: #ffc53b; }  /* crown gold */
.tile[href*="about"]     { --u-glow: #c14bff; --neon: #c14bff; }  /* magenta, brighter than the page violet */

/* Borders pick the colour up too, so an unlit tile still reads as
   its own thing rather than one of five identical panes. */
.tile[href*="giveaway"] { border-color: rgba(255, 47, 77, .30); }
.tile[href*="socials"]  { border-color: rgba(75, 184, 255, .30); }
.tile[href*="stake"]    { border-color: rgba(255, 197, 59, .30); }
.tile[href*="about"]    { border-color: rgba(193, 75, 255, .30); }
.tile[href*="kick.com"] { border-color: rgba(83, 252, 24, .30); }

.tile[href*="giveaway"]:hover { border-color: rgba(255, 47, 77, .60); }
.tile[href*="socials"]:hover  { border-color: rgba(75, 184, 255, .60); }
.tile[href*="stake"]:hover    { border-color: rgba(255, 197, 59, .60); }
.tile[href*="about"]:hover    { border-color: rgba(193, 75, 255, .60); }
.tile[href*="kick.com"]:hover { border-color: rgba(83, 252, 24, .60); }

/* The floor light was tuned against a flat panel; over the nebula it
   needs a little more to read at all. */
.tile::after { opacity: .62; }
.tile:hover::after { opacity: .95; }

/* =========================================================
   Kill the legacy shine sweep
   styles.css and giveaway.css each paint a skewed gradient bar
   on ::before and park it outside the button at left:-120%,
   relying on overflow:hidden to keep it invisible until it
   sweeps across. The glass buttons here set overflow:visible so
   the floor light isn't clipped — which released those bars to
   float around the page as stray dark parallelograms.
   The glass has its own sheen baked into its background, so
   the old sweep is redundant as well as broken.
   ========================================================= */
.btn::before,
.gw-btn::before,
.copy-btn::before,
.social-link::before,
.tile::before { content: none; }

/* ============================================================
   Public chat panel
   Built by js/chat.js. Docks beside the page on wide screens the
   same way the rail does (body padding, not a layout rewrite), and
   goes full-screen overlay below that.
   ============================================================ */
:root {
  --chat-w: 360px;
}

.chat-panel {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 1120;
  width: min(var(--chat-w), 100vw);
  height: 100dvh;
  display: flex;
  flex-direction: column;
  background: linear-gradient(180deg, rgba(13, 10, 28, .97), rgba(8, 6, 15, .97));
  border-left: 1px solid var(--line);
  box-shadow: -18px 0 50px rgba(0, 0, 0, .55);
  /* Above the sticky topbar (1100) so the header and the sign-in dropdown
     cannot paint over the panel — .topbar is a stacking context, so its
     z-index:1300 menu is confined to 1100 relative to this. Still below the
     nav drawer (1150 scrim / 1200 rail) and the account modal (2000), both
     of which should cover chat when open. */
  transform: translateX(100%);
  transition: transform .3s var(--ease);
  /* Not display:none — a hidden-by-transform panel keeps its scroll
     position, so reopening lands where the reader left off. */
  visibility: hidden;
}
.chat-panel.is-open { transform: translateX(0); visibility: visible; }

/* The page shifts rather than being covered, but only where there's
   room for both. Mirrors body.app-body's padding-left for the rail. */
@media (min-width: 1100px) {
  body.app-body { transition: padding-left .28s var(--ease), padding-right .28s var(--ease); }
  body.app-body.chat-open { padding-right: var(--chat-w); }
}

.chat-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  padding: 1rem 1rem .75rem;
  border-bottom: 1px solid var(--line);
  flex: 0 0 auto;
}
.chat-head h2 {
  margin: 0;
  font-family: var(--font-heading);
  font-size: .95rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-primary);
  text-shadow: 0 0 10px rgba(124, 59, 255, .55);
}
.chat-close {
  background: none;
  border: 0;
  color: var(--text-muted);
  cursor: pointer;
  padding: .25rem;
  display: inline-flex;
  border-radius: 8px;
}
.chat-close svg { width: 18px; height: 18px; }
.chat-close:hover { color: var(--text-primary); }

.chat-scroll {
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: .75rem .75rem 0;
}
.chat-scroll::-webkit-scrollbar { width: 6px; }
.chat-scroll::-webkit-scrollbar-thumb { background: rgba(124, 59, 255, .35); border-radius: 99px; }

.chat-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .55rem; }

.chat-msg { display: flex; gap: .55rem; align-items: flex-start; }

.chat-avatar {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  overflow: hidden;
  background: rgba(124, 59, 255, .25);
  border: 1px solid var(--line);
  display: grid;
  place-items: center;
  font-size: .8rem;
  font-weight: 700;
  color: var(--text-primary);
}
.chat-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }

.chat-body {
  flex: 1 1 auto;
  min-width: 0;
  background: rgba(255, 255, 255, .04);
  border: 1px solid rgba(255, 255, 255, .06);
  border-radius: 12px;
  padding: .45rem .6rem .5rem;
}
.chat-meta { display: flex; align-items: baseline; gap: .4rem; }
.chat-name {
  font-weight: 700;
  font-size: .82rem;
  /* Long names must not push the timestamp off the panel. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.chat-badge {
  font-size: .6rem;
  font-weight: 800;
  letter-spacing: .06em;
  padding: .1rem .3rem;
  border-radius: 4px;
  background: rgba(83, 252, 24, .18);
  color: var(--secondary-color);
  flex: 0 0 auto;
}
.chat-time { margin-left: auto; font-size: .68rem; color: var(--text-muted); flex: 0 0 auto; }
.chat-text {
  margin: .15rem 0 0;
  font-size: .85rem;
  line-height: 1.4;
  color: var(--text-secondary);
  /* Unbroken strings (pasted links, keyboard mashing) would otherwise
     widen the bubble past the panel. */
  overflow-wrap: anywhere;
}

.chat-empty { text-align: center; color: var(--text-muted); font-size: .82rem; padding: 2rem 1rem; margin: 0; }

.chat-jump {
  margin: .4rem .75rem 0;
  padding: .35rem .7rem;
  border-radius: 99px;
  border: 1px solid var(--line-strong);
  background: rgba(124, 59, 255, .2);
  color: var(--text-primary);
  font-size: .75rem;
  cursor: pointer;
  flex: 0 0 auto;
}

.chat-flash {
  margin: .4rem .75rem 0;
  font-size: .75rem;
  color: #ffb4b4;
  text-align: center;
  flex: 0 0 auto;
}

.chat-rules { flex: 0 0 auto; border-top: 1px solid var(--line); }
.chat-rules summary {
  cursor: pointer;
  padding: .6rem .9rem;
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-muted);
  list-style: none;
}
.chat-rules summary::-webkit-details-marker { display: none; }
.chat-rules summary::after { content: ' \25BE'; }
.chat-rules[open] summary::after { content: ' \25B4'; }
.chat-rules ul { margin: 0; padding: 0 1.1rem .8rem 2rem; color: var(--text-muted); font-size: .76rem; line-height: 1.5; }

/* [hidden] is display:none at (0,0,1); a class rule that sets display beats
   it, so el.hidden = true silently does nothing. Restate it per component
   rather than trusting the attribute alone. */
.chat-compose[hidden], .chat-signin[hidden], .chat-jump[hidden], .chat-fab-dot[hidden] { display: none; }

.chat-compose {
  flex: 0 0 auto;
  display: flex;
  gap: .4rem;
  padding: .7rem .75rem calc(.7rem + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
}
.chat-input {
  flex: 1 1 auto;
  min-width: 0;
  padding: .55rem .8rem;
  border-radius: 99px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, .05);
  color: var(--text-primary);
  font: inherit;
  font-size: .85rem;
}
.chat-input:focus { outline: none; border-color: var(--primary-light); box-shadow: 0 0 0 3px rgba(124, 59, 255, .2); }
.chat-input::placeholder { color: var(--text-muted); }
.chat-send {
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: rgba(124, 59, 255, .28);
  color: var(--text-primary);
  cursor: pointer;
  display: grid;
  place-items: center;
}
.chat-send svg { width: 16px; height: 16px; }
.chat-send:hover { background: rgba(124, 59, 255, .45); box-shadow: var(--glow); }
.chat-send:disabled { opacity: .5; cursor: default; }

.chat-signin { flex: 0 0 auto; padding: .8rem .75rem calc(.8rem + env(safe-area-inset-bottom)); border-top: 1px solid var(--line); }
.chat-signin-btn {
  display: block;
  text-align: center;
  padding: .6rem 1rem;
  border-radius: 10px;
  background: var(--secondary-color);
  color: #06210a;
  font-weight: 700;
  font-size: .84rem;
  text-decoration: none;
  box-shadow: 0 0 18px rgba(83, 252, 24, .45);
}
.chat-signin-btn:hover { filter: brightness(1.08); }

.chat-fab {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 1121;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: linear-gradient(160deg, rgba(124, 59, 255, .95), rgba(90, 31, 224, .95));
  color: #fff;
  cursor: pointer;
  display: grid;
  place-items: center;
  box-shadow: var(--glow), var(--shadow-md);
  transition: transform .2s var(--ease), right .3s var(--ease);
}
.chat-fab svg { width: 22px; height: 22px; }
.chat-fab:hover { transform: translateY(-2px); }
.chat-fab-dot {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--secondary-color);
  box-shadow: 0 0 8px rgba(83, 252, 24, .9);
}
/* Ride along with the docked panel instead of sitting on top of it. */
@media (min-width: 1100px) {
  body.chat-open .chat-fab { right: calc(var(--chat-w) + 1rem); }
}

@media (prefers-reduced-motion: reduce) {
  .chat-panel, .chat-fab, body.app-body { transition: none; }
}

/* --- chat: emoji picker + moderation ------------------------------- */
.chat-compose { position: relative; }

.chat-emoji-btn {
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  align-self: center;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, .05);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  display: grid;
  place-items: center;
  padding: 0;
}
.chat-emoji-btn:hover { border-color: var(--primary-light); }

.chat-emoji-panel {
  position: absolute;
  bottom: calc(100% + .4rem);
  left: .75rem;
  right: .75rem;
  z-index: 2;
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: .15rem;
  padding: .5rem;
  border-radius: 12px;
  border: 1px solid var(--line-strong);
  background: var(--surface-solid);
  box-shadow: var(--shadow-md);
}
.chat-emoji-panel[hidden] { display: none; }
.chat-emoji {
  border: 0;
  background: none;
  font-size: 1.05rem;
  line-height: 1.5;
  cursor: pointer;
  border-radius: 6px;
  padding: 0;
}
.chat-emoji:hover { background: rgba(124, 59, 255, .3); }

/* The delete control only exists for admins, and only shows on hover so it
   doesn't clutter the read view. Kept reachable by keyboard via :focus. */
.chat-del {
  flex: 0 0 auto;
  align-self: flex-start;
  margin-top: .3rem;
  width: 24px;
  height: 24px;
  border-radius: 6px;
  border: 1px solid transparent;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
  display: grid;
  place-items: center;
  opacity: 0;
  transition: opacity .15s var(--ease), color .15s var(--ease);
}
.chat-del svg { width: 14px; height: 14px; }
.chat-msg:hover .chat-del,
.chat-del:focus-visible { opacity: 1; }
.chat-del:hover { color: #ff8a8a; border-color: rgba(255, 138, 138, .4); }

/* Touch devices have no hover, so the control would be unreachable. */
@media (hover: none) {
  .chat-panel.can-moderate .chat-del { opacity: .65; }
}

/* --- admin gate ----------------------------------------------------
   The token field had no rule matching it at all, so it rendered with
   browser defaults: a white box with black text sitting on the dark
   admin page. Scoped to #adminGate so it can't reach public pages. */
#adminGate {
  max-width: 460px;
  margin: 3rem auto 0;
  padding: 2rem;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--surface);
  backdrop-filter: blur(8px);
}
#adminGate h1 { margin: 0; font-family: var(--font-heading); }
#adminGate label {
  font-size: .82rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-muted);
}
#adminGate input {
  margin-top: .4rem;
  padding: .65rem .8rem;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, .05);
  color: var(--text-primary);
  font: inherit;
  font-size: .95rem;
  /* The label is uppercased; the value typed into the field must not be. */
  text-transform: none;
  letter-spacing: normal;
}
#adminGate input:focus {
  outline: none;
  border-color: var(--primary-light);
  box-shadow: 0 0 0 3px rgba(124, 59, 255, .2);
}
#adminGate input::placeholder { color: var(--text-muted); }

/* --- chat on phones -------------------------------------------------
   Below the docking breakpoint the panel is an overlay, and two things
   measured wrong on a 375px screen:

   1. A fixed 360px panel left a useless 15px sliver of page down one
      side and pinned its right edge to the initial containing block
      rather than the visual viewport. Spanning left/right removes the
      fixed width from the equation entirely.
   2. The floating button stayed bottom-right, directly on top of the
      composer — measured overlapping the send button (FAB 323-375,
      send 341-379). Tapping send would close the chat instead. The
      panel has its own close button, so the FAB is redundant while
      it's open. */
body.chat-locked { overflow: hidden; }

@media (max-width: 1099px) {
  .chat-panel {
    left: 0;
    right: 0;
    width: auto;
  }
  /* Rounded screen corners and gesture bars eat the outermost few
     pixels on a modern phone, which is exactly where the send button
     sits. Pad by the device safe area rather than a guessed constant. */
  .chat-compose,
  .chat-signin {
    padding-left: calc(.75rem + env(safe-area-inset-left));
    padding-right: calc(.75rem + env(safe-area-inset-right));
  }
  .chat-panel.is-open ~ .chat-fab,
  body.chat-open .chat-fab {
    display: none;
  }
}

/* --- embedded Kick player -------------------------------------------
   The markup shipped without these rules, so the iframe fell back to its
   intrinsic 300x150 default sitting inline in an 800px-wide box — the
   stream was technically embedded and effectively unwatchable.

   aspect-ratio on the wrapper rather than a padding-top hack: the player
   is 16:9, and this keeps it that shape at every width without JS. */
.connect-stream {
  grid-column: 1 / -1;
  margin-top: var(--spacing-md);
}

.stream-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--line-strong);
  background: #000;
  box-shadow: var(--shadow-lg), 0 0 30px rgba(83, 252, 24, .18);
}

.stream-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  /* iframes are inline by default, which leaves a descender gap under the
     player even once it's sized correctly. */
  display: block;
}

/* Tall phones: a 16:9 player plus the page header leaves very little of
   the stream visible, so cap it and let it letterbox rather than shrink
   to a stripe. */
@media (max-width: 640px) {
  .stream-frame { aspect-ratio: 16 / 10; }
}

/* --- Stake.us footer mark -------------------------------------------
   Two Stake links sit side by side in the footer, and at 20px the glyphs
   read as the same shape. Colour is what actually tells them apart, so
   .us carries the red that was asked for while .com keeps the house
   green — the badge on the mark is a secondary cue, not the main one. */
.social-link.is-stake-us { color: #ff4d4d !important; }
.social-link.is-stake-us svg {
  filter: drop-shadow(0 0 6px rgba(255, 77, 77, .85))
    drop-shadow(0 0 14px rgba(255, 77, 77, .45));
}
.social-link.is-stake-us:hover,
.social-link.is-stake-us:focus-visible {
  color: #ff6b6b !important;
}
.social-link.is-stake-us:hover svg,
.social-link.is-stake-us:focus-visible svg {
  filter: drop-shadow(0 0 9px rgba(255, 77, 77, 1))
    drop-shadow(0 0 22px rgba(255, 77, 77, .7));
}
