/* ==========================================================================
   MathClash — polish layer (v13 · "static art survives")
   Loaded AFTER all other stylesheets (see index.html). Pure additive
   presentation: screen transitions, streak milestones, micro-inter-
   actions, ambience, celebrations. Nothing here changes layout
   dimensions by more than a transform, so the app's own logic and hit
   targets are untouched.

   v13 changes:
   - REDUCED MOTION KEEPS THE ART: the kill-switch block now freezes
     only MOVEMENT. Static decor (icon chips, tab icons, corner
     brackets, emblem watermarks, math rails, flavor ticker) mounts for
     everyone — "Reduce motion" stops things from moving, it does not
     strip the room bare. Only the inherently-animated layers (aurora,
     grain, cursor trail, ghosts, tilt) stay fully off.
   - MATH RAILS, THREE TIERS: the gutter glyph rails used to exist only
     ≥1500px, so laptops and phones never saw them. Now: full 5-glyph
     rails + MATHCLASH label in the content gutters from 1360px, slim
     3-glyph edge strips from 760px, and a whisper pair of edge glyphs
     on phones that lives inside the app's own 13px page padding.
   - TAB ICONS (ALMOST) EVERYWHERE: the ≤560px hide is gone; phones
     get a compact 10px form (verified no clipping at 390px, where
     the app renders the strip as a two-column grid). The single
     exception is the 881–1160px two-column band, where the tabs are
     too narrow for icon + "Leaderboard" together — there the labels
     win (see the comment at the rule).

   v11 changes:
   - TAB TRANSITIONS v3: the shared-axis choreography is replaced by
     crisp directional SLIDES — the outgoing panel's snapshot glides
     fully to the side and fades away, the incoming cards slide in
     from the opposite side. Flat translateX + opacity only (no
     rotateY / perspective / scale; the light sweep is gone) so text
     stays pixel-crisp at every frame of the move.
   - INTERIOR DECOR: the game shell's lobby surfaces get mint icon
     chips next to titles, mini icons in the tab strip + mode toggles,
     corner brackets and watermark emblems on lobby cards, floating
     math glyphs in the wide-screen gutters, and a rotating flavor
     ticker that fades out whenever a play surface is active.

   v10 changes (kept — the delivery site's motion language):
   - LANDING STUDIO: the "Train your edge." page gets presentation-
     site entrances (h1 wipe, staggered copy, card swing-in, orbit
     scale-ins, feature flips), a 3D tilt on the problem preview card
     that leans toward the hovered corner with a cursor-tracking glare
     and layered translateZ depth, a magnetic hero CTA, and cursor-
     driven parallax on the float chips / orbit rings / copy column
     (all engine-driven from polish.js via the individual `translate`
     property, so the app's own transforms and rise animations keep
     working untouched).
   - CUSTOM CURSOR: the precise mint dot + spring-trailing ring on the
     landing and auth screens only (fine pointers, motion allowed).
     Native inputs keep their caret; the app shell keeps the native
     cursor so solving problems never feels like a side show.
   - FILM GRAIN: the delivery site's subtle animated grain overlay.

   v9 changes (kept):
   - STREAK MILESTONES: at exactly 10 / 30 / 50 / 100 login days the
     navbar badge bursts, ring shockwaves expand, the screen edges
     flash in the tier color and a count-up banner takes the stage
     (overlay built by polish.js; tiers: 10 hot red, 30 violet,
     50 purple, 100 gold "legendary").
   - SCREEN TRANSITIONS: a soft light sweep crosses the page on every
     top-level screen swap; duel/party sub-screens rise in; every tab
     switch staggers the activated panel's cards.
   - JUICE: duel score numbers pop, gold pips flare, button presses
     ring a halo, waiting states breathe, the streak flame flickers.
   - AMBIENCE: a dim aurora layer breathes behind everything; the
     app's floating formulas parallax with the pointer (polish.js).
   - FIXES: victory celebration now hooks the real end banner
     (.duel-end-banner — Victory!/Defeat/Draw!); party standings
     stagger now targets the real row class (.party-row).

   Reduced motion: every animation is wrapped in a global
   @media (prefers-reduced-motion: reduce) kill-switch at the bottom
   (plus the app's own switch). The companion polish.js also skips
   confetti, overlays, sweeps, tilt, cursor and parallax for those
   users.
   ========================================================================== */

/* ---------- 1. Mount: screens rise, the navbar drops in ---------- */
.app-shell,
.auth-page-content,
.landing-screen,
.info-screen {
  animation: mc-rise 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.auth-page-content { animation-duration: 0.55s; }
.navbar {
  animation: mc-nav-in 0.6s cubic-bezier(0.22, 1, 0.36, 1) 0.08s both;
}
@keyframes mc-rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@keyframes mc-nav-in {
  from { transform: translateY(-100%); opacity: 0; }
  to   { transform: none; opacity: 1; }
}
/* Landing + auth content cascades (generic child stagger).
   The landing screen renders a single .landing-shell wrapper — its
   children (hero, features, footer) are the cascade targets. */
.landing-screen .landing-shell > * {
  animation: mc-card-rise 0.6s cubic-bezier(0.22, 1, 0.36, 1) 0.38s both;
}
.landing-screen .landing-shell > *:nth-child(1) { animation-delay: 0.06s; }
.landing-screen .landing-shell > *:nth-child(2) { animation-delay: 0.12s; }
.landing-screen .landing-shell > *:nth-child(3) { animation-delay: 0.18s; }
.landing-screen .landing-shell > *:nth-child(4) { animation-delay: 0.24s; }
.landing-screen .landing-shell > *:nth-child(5) { animation-delay: 0.30s; }
.landing-screen .landing-shell > *:nth-child(6) { animation-delay: 0.36s; }
.auth-layout > * {
  animation: mc-card-rise 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.14s both;
}
.auth-layout > *:first-child { animation-delay: 0.07s; }
@keyframes mc-card-rise {
  from { opacity: 0; transform: translateY(12px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}

/* ---------- 2. Screen sweep: a light pass on top-level swaps ---------- */
#mc-sweep {
  position: fixed;
  inset: 0;
  z-index: 3;               /* above the screens (z 1), below toasts */
  pointer-events: none;
  overflow: hidden;
}
#mc-sweep i {
  position: absolute;
  inset: -20%;
  display: block;
  background: linear-gradient(105deg,
      transparent 40%,
      rgba(180, 246, 241, 0.04) 45%,
      rgba(180, 246, 241, 0.08) 50%,
      rgba(122, 167, 255, 0.05) 55%,
      transparent 60%);
  transform: translateX(-75%);
  animation: mc-sweep 0.55s cubic-bezier(0.4, 0, 0.2, 1) both;
}
@keyframes mc-sweep {
  to { transform: translateX(75%); }
}

/* ---------- 3. Aurora ambience (mounted by polish.js before #root) ----
   Sizes are capped in px as well as vmax so 4K screens don't allocate
   enormous compositor layers. */
#mc-aurora {
  position: fixed;
  inset: 0;
  z-index: 0;               /* above the body gradient, under everything */
  pointer-events: none;
  overflow: hidden;
}
#mc-aurora i {
  position: absolute;
  display: block;
  border-radius: 50%;
}
#mc-aurora .b1 {
  width: min(60vmax, 900px); height: min(60vmax, 900px);
  left: -18vmax; top: -22vmax;
  background: radial-gradient(circle,
      rgba(61, 120, 216, 0.14) 0%, rgba(61, 120, 216, 0.05) 42%, transparent 68%);
  animation: mc-aur-1 46s ease-in-out infinite alternate;
}
#mc-aurora .b2 {
  width: min(52vmax, 780px); height: min(52vmax, 780px);
  right: -20vmax; top: 8vmax;
  background: radial-gradient(circle,
      rgba(103, 213, 172, 0.11) 0%, transparent 66%);
  animation: mc-aur-2 58s ease-in-out infinite alternate;
}
#mc-aurora .b3 {
  width: min(46vmax, 700px); height: min(46vmax, 700px);
  left: 24vmax; bottom: -24vmax;
  background: radial-gradient(circle,
      rgba(246, 199, 106, 0.08) 0%, transparent 64%);
  animation: mc-aur-3 52s ease-in-out infinite alternate;
}
@keyframes mc-aur-1 { to { transform: translate3d(9vmax, 7vmax, 0) scale(1.12); } }
@keyframes mc-aur-2 { to { transform: translate3d(-11vmax, 6vmax, 0) scale(0.94); } }
@keyframes mc-aur-3 { to { transform: translate3d(-7vmax, -9vmax, 0) scale(1.08); } }

/* ---------- 4. Cards: hover lift + deeper shadow ---------- */
.card {
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.card:hover {
  transform: translateY(-2px);
  border-color: var(--border-bright, #3f7598);
  box-shadow: 0 22px 70px #01071180, 0 0 0 1px #4d8dff14;
}
/* Cards that hold live state shouldn't dance on hover. */
.problem-card:hover,
.duel-active-card:hover,
.party-card:hover {
  transform: none;
}

/* ---------- 5. Buttons: press, hover, focus, halo ---------- */
.btn {
  /* Extends (not replaces) the app's own transition list so its hover
     lift, press scale and color fades all keep animating. */
  transition: transform 0.12s ease, box-shadow 0.15s ease,
              background 0.15s ease, border-color 0.15s ease,
              filter 0.15s ease, color 0.2s ease;
}
.btn:hover:not(:disabled) {
  transform: translateY(-1px);
  filter: brightness(1.06);
}
.btn:active:not(:disabled) {
  transform: translateY(0) scale(0.97);
  filter: brightness(0.97);
}
.btn:focus-visible,
.mode-tab:focus-visible,
.duel-kind-btn:focus-visible,
a:focus-visible,
input:focus-visible,
button:focus-visible {
  outline: 2px solid var(--focus, #b4f6f1);
  outline-offset: 2px;
}
.btn-primary:not(:disabled) {
  box-shadow: 0 6px 18px #3d78d833;
}
.btn-primary:hover:not(:disabled) {
  box-shadow: 0 8px 24px #3d78d855;
}
.btn-success:not(:disabled) {
  box-shadow: 0 6px 18px #67d5ac33;
}
/* Press halo — outline-based, so it never fights the app's own
   button box-shadows. Class added by polish.js on pointerdown. */
.mc-press {
  animation: mc-press-halo 0.5s ease-out;
}
@keyframes mc-press-halo {
  0%   { outline: 2px solid rgba(126, 230, 224, 0.55); outline-offset: 0; }
  100% { outline: 2px solid rgba(126, 230, 224, 0); outline-offset: 10px; }
}

/* ---------- 6. Mode tabs: the active pill gets a soft glow ---------- */
.mode-tab {
  /* Full list, matching the app's own transition so the indicator,
     hover lift and glow all keep animating smoothly. */
  transition: color 0.18s ease, background 0.18s ease,
              border-color 0.2s ease, box-shadow 0.2s ease,
              transform 0.22s cubic-bezier(0.22, 1, 0.36, 1);
}
.mode-tab.active {
  text-shadow: 0 0 18px #6aa7ff66;
}

/* ---------- 7. Success / error feedback: arrival animations ---------- */
.feedback {
  animation: mc-pop 0.32s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
.feedback.ok {
  box-shadow: inset 0 0 0 1px #67d5ac40, 0 0 24px #67d5ac1a;
}
@keyframes mc-pop {
  0%   { opacity: 0; transform: translateY(6px) scale(0.98); }
  100% { opacity: 1; transform: none; }
}
.feedback.err {
  animation: mc-shake 0.36s ease both;
}
@keyframes mc-shake {
  0%, 100% { transform: translateX(0); }
  20%  { transform: translateX(-5px); }
  40%  { transform: translateX(5px); }
  60%  { transform: translateX(-3px); }
  80%  { transform: translateX(3px); }
}

/* ---------- 8. Timer urgency (class added by polish.js) ----------
   Only a genuine countdown's final 10 seconds ever gets this class —
   the daily/duel elapsed clocks count UP and stay calm (v8.1 fix). */
.timer.mc-urgent {
  color: var(--red, #ff7f87);
  border-color: #ff7f8766;
  box-shadow: 0 0 16px #ff7f8726;
  animation: mc-tick 1s steps(2, jump-none) infinite;
}
@keyframes mc-tick {
  0%   { opacity: 1; }
  50%  { opacity: 0.45; }
  100% { opacity: 1; }
}

/* ---------- 9. Fresh problem text: gentle slide-in ---------- */
.problem-copy.mc-fresh {
  animation: mc-slide-in 0.34s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes mc-slide-in {
  from { opacity: 0; transform: translateX(8px); }
  to   { opacity: 1; transform: none; }
}

/* ---------- 10. Leaderboard: stamped metal medals for the podium ---------
   The .rank cell keeps its layout (table column untouched); a medal
   disc is painted BEHIND the rank number via ::before (z-index -1
   inside a td-owned stacking context). Gold gets an animated sheen
   sweep via ::after. The app's own small medal icons beside the player
   names are untouched. */
.lb-table tbody tr:nth-child(1) .rank,
.lb-table tbody tr:nth-child(2) .rank,
.lb-table tbody tr:nth-child(3) .rank {
  position: relative;
  z-index: 0;
  text-align: center;
  font-weight: 800;
}
.lb-table tbody tr:nth-child(1) .rank::before,
.lb-table tbody tr:nth-child(2) .rank::before,
.lb-table tbody tr:nth-child(3) .rank::before {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 27px;
  height: 27px;
  border-radius: 50%;
  z-index: -1;
  transition: filter 0.2s ease;
}
/* Gold — glossy, warm, with an animated sheen sweep. */
.lb-table tbody tr:nth-child(1) .rank {
  color: #4a3305;
}
.lb-table tbody tr:nth-child(1) .rank::before {
  background: radial-gradient(circle at 32% 28%,
              #fff7d6 0%, #ffe08a 26%, #f5c84c 55%,
              #d99e26 76%, #9c6b12 100%);
  box-shadow:
    inset 0 1px 2px rgba(255, 252, 230, 0.65),
    inset 0 -2px 3px rgba(90, 55, 0, 0.5),
    inset 0 0 0 1px rgba(120, 80, 10, 0.55),
    0 0 0 1px rgba(255, 224, 138, 0.28),
    0 0 14px rgba(245, 200, 76, 0.42);
}
.lb-table tbody tr:nth-child(1) .rank::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 27px;
  height: 27px;
  border-radius: 50%;
  z-index: -1;
  background: linear-gradient(115deg,
              transparent 34%, rgba(255, 255, 255, 0.5) 46%,
              rgba(255, 255, 255, 0.08) 54%, transparent 64%);
  background-size: 220% 100%;
  animation: mc-sheen 3.4s ease-in-out infinite;
}
@keyframes mc-sheen {
  0%   { background-position: 200% 0; }
  55%  { background-position: -120% 0; }
  100% { background-position: -120% 0; }
}
/* Silver — cool, brushed. */
.lb-table tbody tr:nth-child(2) .rank {
  color: #2c3b4d;
}
.lb-table tbody tr:nth-child(2) .rank::before {
  background: radial-gradient(circle at 32% 28%,
              #ffffff 0%, #eef4fb 26%, #c6d4e2 55%,
              #9fb2c4 76%, #74889e 100%);
  box-shadow:
    inset 0 1px 2px rgba(255, 255, 255, 0.75),
    inset 0 -2px 3px rgba(40, 60, 90, 0.45),
    inset 0 0 0 1px rgba(90, 110, 140, 0.5),
    0 0 0 1px rgba(230, 240, 252, 0.22),
    0 0 12px rgba(198, 212, 226, 0.3);
}
/* Bronze — earthy, warm. */
.lb-table tbody tr:nth-child(3) .rank {
  color: #4a2a10;
}
.lb-table tbody tr:nth-child(3) .rank::before {
  background: radial-gradient(circle at 32% 28%,
              #ffdfb6 0%, #eeb886 26%, #d29a6b 55%,
              #a96a3a 76%, #77431d 100%);
  box-shadow:
    inset 0 1px 2px rgba(255, 235, 208, 0.6),
    inset 0 -2px 3px rgba(70, 35, 10, 0.5),
    inset 0 0 0 1px rgba(100, 55, 20, 0.55),
    0 0 0 1px rgba(240, 195, 154, 0.25),
    0 0 12px rgba(210, 154, 107, 0.32);
}
/* Rows: hover tint + your-row tint; medals brighten slightly on hover. */
.lb-table tbody tr {
  transition: background 0.2s ease;
}
.lb-table tbody tr:hover {
  background: #10213966;
}
.lb-table tbody tr.me {
  background: #4d8dff0f;
}
.lb-table tbody tr:hover .rank::before {
  filter: brightness(1.1);
}

/* ---------- 11. List rows + party roster: stagger-in ----------
   (v9 fix: party standings rows are li.party-row, not .party-standings-row) */
.lb-table tbody tr,
.party-roster .party-player,
.party-standings .party-row {
  animation: mc-row-in 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.lb-table tbody tr:nth-child(1) { animation-delay: 0.02s; }
.lb-table tbody tr:nth-child(2) { animation-delay: 0.06s; }
.lb-table tbody tr:nth-child(3) { animation-delay: 0.10s; }
.lb-table tbody tr:nth-child(4) { animation-delay: 0.14s; }
.lb-table tbody tr:nth-child(5) { animation-delay: 0.18s; }
.party-roster .party-player:nth-child(1) { animation-delay: 0.02s; }
.party-roster .party-player:nth-child(2) { animation-delay: 0.06s; }
.party-roster .party-player:nth-child(3) { animation-delay: 0.10s; }
.party-roster .party-player:nth-child(4) { animation-delay: 0.14s; }
.party-roster .party-player:nth-child(5) { animation-delay: 0.18s; }
.party-roster .party-player:nth-child(6) { animation-delay: 0.22s; }
.party-roster .party-player:nth-child(7) { animation-delay: 0.26s; }
.party-roster .party-player:nth-child(8) { animation-delay: 0.30s; }
@keyframes mc-row-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}

/* ---------- 11b. Party podium: rise + bar growth ---------- */
.party-podium .party-step {
  animation: mc-podium-rise 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
.party-podium .party-step.place-2 { animation-delay: 0.05s; }
.party-podium .party-step.place-1 { animation-delay: 0.15s; }
.party-podium .party-step.place-3 { animation-delay: 0.25s; }
@keyframes mc-podium-rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
.party-podium .party-step-bar span {
  animation: mc-grow 0.6s cubic-bezier(0.22, 1, 0.36, 1) 0.3s both;
}
@keyframes mc-grow {
  from { transform: scaleY(0.4); }
  to   { transform: scaleY(1); }
}
/* First place: the gold bar softly breathes. */
.party-podium .party-step.place-1 .party-step-bar {
  box-shadow: 0 0 22px #f5c84c44;
  animation: mc-gold-pulse 2.6s ease-in-out infinite;
}
@keyframes mc-gold-pulse {
  0%, 100% { box-shadow: 0 0 22px #f5c84c44; }
  50%      { box-shadow: 0 0 34px #f5c84c77; }
}

/* ---------- 12. Duel end banners: Victory shimmer / Defeat / Draw ------
   (v9 fix: the real end screen renders div.duel-end-banner, not an
   h2.duel-title — classes added by polish.js.) */
.duel-end-banner.mc-victory,
h2.duel-title.mc-victory {
  animation: mc-victory-in 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
@keyframes mc-victory-in {
  0%   { opacity: 0; transform: scale(0.86); }
  100% { opacity: 1; transform: none; }
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .duel-end-banner.mc-victory,
  h2.duel-title.mc-victory {
    background: linear-gradient(100deg,
                #f5c84c 15%, #fff3c4 38%, #f5c84c 55%,
                #ffe9a3 72%, #f5c84c 90%);
    background-size: 250% 100%;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    animation: mc-victory-in 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) both,
               mc-shimmer-text 3s linear infinite;
  }
}
@keyframes mc-shimmer-text {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}
.duel-end-banner.mc-defeat {
  color: var(--red, #ff7f87);
  animation: mc-banner-drop 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.duel-end-banner.mc-draw {
  color: var(--cyan, #7ee6e0);
  animation: mc-banner-drop 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes mc-banner-drop {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* ---------- 13. Duel / party sub-screens rise in on mount ----------
   (class added by polish.js; removed again after the entrance so it
   can never collide with the app's own .shake on wrong answers). */
.mc-screen-in {
  animation: mc-screen-in 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes mc-screen-in {
  from { opacity: 0; transform: translateY(14px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}
/* Waiting states breathe while the duel syncs. */
.duel-ready {
  animation: mc-breathe 1.7s ease-in-out infinite;
}
@keyframes mc-breathe {
  0%, 100% { opacity: 0.6; }
  50%      { opacity: 1; }
}

/* ---------- 14. Tab choreography v3: crisp directional slides ------
   (.mc-panel-enter + data-mc-dir="fwd|back" are added by polish.js
   when a .mode-panel gains .active — panels stay mounted, only their
   classes flip. v11: FLAT translateX only — no rotateY, no
   perspective, no scale — because text travelling through 3D space
   rasterizes at an angle and reads blurry mid-flight. Hidden panels
   cost nothing.) */
.mc-panel-enter[data-mc-dir] > * {
  animation: mc-card-slide-fwd 0.45s cubic-bezier(0.22, 1, 0.36, 1) 0.06s backwards;
}
.mc-panel-enter[data-mc-dir="back"] > * {
  animation-name: mc-card-slide-back;
}
.mc-panel-enter > *:nth-child(1) { animation-delay: 0.02s; }
.mc-panel-enter > *:nth-child(2) { animation-delay: 0.06s; }
.mc-panel-enter > *:nth-child(3) { animation-delay: 0.10s; }
.mc-panel-enter > *:nth-child(4) { animation-delay: 0.14s; }
.mc-panel-enter > *:nth-child(5) { animation-delay: 0.18s; }
.mc-panel-enter > *:nth-child(6) { animation-delay: 0.22s; }
.mc-panel-enter > *:nth-child(7) { animation-delay: 0.26s; }
.mc-panel-enter > *:nth-child(8) { animation-delay: 0.30s; }

/* The outgoing panel's snapshot (built by polish.js at the moment the
   classes flip, fixed-positioned over the panel slot, removed after
   ~360 ms). Glides fully to the side in the travel direction and
   fades — flat, so the copy never blurs. */
.mc-ghost {
  position: fixed;
  z-index: 26;
  pointer-events: none;
  box-sizing: border-box;
  will-change: transform, opacity;
  animation: mc-ghost-slide-fwd 0.32s cubic-bezier(0.5, 0, 0.8, 0.4) forwards;
}
.mc-ghost[data-mc-dir="back"] { animation-name: mc-ghost-slide-back; }
/* v12: a freshly cloned subtree RESTARTS every animation it carries —
   the app's .duel-card/.leaderboard-page run "rise" (from translateY
   13px, opacity 0) and .problem-card runs "card-enter", so the ghost
   used to spawn its content a few px LOW and re-rise while sliding
   out ("teleports down, then slides and fades"). Freezing every
   descendant at its resting pose pins the snapshot to exactly what
   the user was looking at; only the root keeps its slide-out. */
.mc-ghost *,
.mc-ghost *::before,
.mc-ghost *::after {
  animation: none !important;
  transition: none !important;
}

/* ---------- 15. Juice: score pops + pip flares (classes via polish.js) --
   display:inline-block makes the scale animation work on inline
   elements (b.party-score, strong) without shifting their layout. */
.mc-pop-num {
  display: inline-block;
  animation: mc-num-pop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes mc-num-pop {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.3); color: #ffd76e; }
  100% { transform: scale(1); }
}
.mc-num-down {
  display: inline-block;
  animation: mc-num-down 0.5s ease;
}
@keyframes mc-num-down {
  35%  { transform: scale(0.9); color: #ff7f87; }
  100% { transform: scale(1); }
}
.mc-pip-in {
  animation: mc-pip-in 0.55s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes mc-pip-in {
  0%   { transform: scale(0.3); box-shadow: 0 0 0 0 rgba(245, 200, 76, 0.7); }
  45%  { transform: scale(1.45); }
  100% { transform: scale(1); box-shadow: 0 0 0 12px rgba(245, 200, 76, 0); }
}

/* ---------- 16. The streak flame flickers (always-on ambience) -------- */
.streak-badge .streak-flame {
  animation: mc-flicker 2.8s ease-in-out infinite;
  transform-origin: 50% 100%;
}
@keyframes mc-flicker {
  0%, 100% { transform: scale(1) rotate(0deg); }
  22% { transform: scale(1.07, 0.93) rotate(-1.4deg); }
  45% { transform: scale(0.95, 1.05) rotate(1.1deg); }
  68% { transform: scale(1.04, 0.97) rotate(-0.7deg); }
}
/* Milestone burst on the badge (class added by polish.js). */
.streak-badge.mc-streak-hot {
  animation: mc-badge-burst 1.3s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
@keyframes mc-badge-burst {
  0%   { transform: scale(1); }
  30%  { transform: scale(1.32); }
  55%  { transform: scale(0.94); }
  100% { transform: scale(1); }
}
.streak-badge.mc-streak-hot .streak-flame {
  animation: mc-flame-flare 1.1s ease both;
}
@keyframes mc-flame-flare {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.55) rotate(-4deg); filter: brightness(1.6) drop-shadow(0 0 10px rgba(255, 200, 80, 0.8)); }
  100% { transform: scale(1); }
}

/* ---------- 17. STREAK MILESTONE OVERLAY (built by polish.js) ----------
   Fires at exactly 10 / 30 / 50 / 100 login days. Tier colors:
   10 hot red · 30 violet · 50 purple · 100 gold "legendary". */
#mc-milestone {
  position: fixed;
  inset: 0;
  z-index: 9998;             /* under the confetti canvas (9999) */
  pointer-events: none;
  display: grid;
  place-items: center;
  overflow: hidden;
}
#mc-milestone[data-tier="10"]  { --ms-c: #ff6479; --ms-c-e: rgba(255, 100, 121, 0.35); }
#mc-milestone[data-tier="30"]  { --ms-c: #cf62d8; --ms-c-e: rgba(207, 98, 216, 0.35); }
#mc-milestone[data-tier="50"]  { --ms-c: #c38aff; --ms-c-e: rgba(195, 138, 255, 0.38); }
#mc-milestone[data-tier="100"] { --ms-c: #f6c76a; --ms-c-e: rgba(246, 199, 106, 0.45); }
.mcs-dim {
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 42%,
      rgba(4, 10, 20, 0.18), rgba(3, 7, 15, 0.62));
  animation: mc-ms-dim var(--ms-dur, 2s) ease both;
}
@keyframes mc-ms-dim {
  0%   { opacity: 0; }
  16%  { opacity: 1; }
  74%  { opacity: 1; }
  100% { opacity: 0; }
}
.mcs-ring {
  position: absolute;
  left: 50%;
  top: 42%;
  width: 14vmin;
  height: 14vmin;
  margin: -7vmin 0 0 -7vmin;
  border-radius: 50%;
  border: 2px solid var(--ms-c, #f5c84c);
  opacity: 0;
  animation: mc-ms-ring 1s cubic-bezier(0.22, 1, 0.36, 1) 0.1s both;
}
.mcs-ring.r2 {
  animation-delay: 0.32s;
  border-width: 1px;
}
@keyframes mc-ms-ring {
  0%   { opacity: 0.85; transform: scale(0.25); }
  100% { opacity: 0; transform: scale(3); }
}
.mcs-edge {
  position: absolute;
  inset: 0;
  animation: mc-ms-edge var(--ms-dur, 2s) ease-out both;
}
@keyframes mc-ms-edge {
  0%   { box-shadow: inset 0 0 0 0 transparent; }
  12%  { box-shadow: inset 0 0 140px 10px var(--ms-c-e, rgba(245, 200, 76, 0.4)); }
  70%  { box-shadow: inset 0 0 60px 0 transparent; }
  100% { box-shadow: inset 0 0 0 0 transparent; }
}
.mcs-banner {
  position: relative;
  text-align: center;
  padding: 0 24px;
  animation: mc-ms-in 0.65s cubic-bezier(0.34, 1.56, 0.64, 1) 0.08s both;
}
@keyframes mc-ms-in {
  0%   { opacity: 0; transform: scale(0.78) translateY(14px); }
  100% { opacity: 1; transform: none; }
}
.mcs-kicker {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: clamp(10px, 1.8vw, 13px);
  letter-spacing: 0.46em;
  text-transform: uppercase;
  color: #9fc0dd;
  margin-bottom: 8px;
  padding-left: 0.46em;
}
.mcs-days {
  font-family: var(--font-sans, system-ui, sans-serif);
  font-weight: 800;
  font-size: clamp(76px, 17vmin, 168px);
  line-height: 0.95;
  color: transparent;
  background: linear-gradient(180deg, #ffffff 8%, var(--ms-c, #f5c84c) 62%);
  -webkit-background-clip: text;
  background-clip: text;
  filter: drop-shadow(0 10px 34px var(--ms-c-e, rgba(245, 200, 76, 0.4)));
}
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .mcs-days { color: var(--ms-c, #f5c84c); background: none; filter: none; }
}
.mcs-word {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: clamp(13px, 2.6vw, 22px);
  letter-spacing: 0.6em;
  padding-left: 0.6em;
  text-transform: uppercase;
  color: #d9ecff;
  margin-top: 10px;
}
#mc-milestone[data-tier="100"] .mcs-word {
  background: linear-gradient(100deg, #f6c76a, #fff3c4, #f6c76a);
  background-size: 200% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: mc-shimmer-text 2.4s linear infinite;
}
.mcs-sub {
  margin-top: 14px;
  color: #a9c6e2;
  font-size: clamp(12px, 2vw, 15px);
}

/* ---------- 18. Confetti canvas (created by polish.js) ---------- */
#mc-confetti {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 9999;
}

/* ---------- 19. Typographic niceties + softer scrollbars ---------- */
::selection {
  background: rgba(61, 120, 216, 0.4);
  color: #ffffff;
}
input,
textarea,
select {
  caret-color: var(--cyan, #7ee6e0);
}
* {
  scrollbar-width: thin;
  scrollbar-color: #3f7598 transparent;
}
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-thumb {
  background: #3f759866;
  border-radius: 8px;
}
*::-webkit-scrollbar-thumb:hover { background: #3f759899; }
*::-webkit-scrollbar-track { background: transparent; }

/* ---------- 21. v10 LANDING STUDIO: entrances (pure CSS — the ----------
   stylesheet is render-blocking, so these run from the very first
   paint with no flash; fill-mode is "backwards" so every element
   hands back to the app's own resting styles when finished). */
.landing-copy .eyebrow {
  animation: mc-copy-in 0.6s cubic-bezier(0.22, 1, 0.36, 1) 0.05s backwards;
}
.landing-copy h1 {
  animation: mc-h1-wipe 0.85s cubic-bezier(0.22, 1, 0.36, 1) 0.12s backwards;
}
.landing-copy .landing-tagline {
  animation: mc-copy-in 0.6s cubic-bezier(0.22, 1, 0.36, 1) 0.32s backwards;
}
.landing-copy .landing-audience {
  animation: mc-copy-in 0.6s cubic-bezier(0.22, 1, 0.36, 1) 0.42s backwards;
}
.landing-copy .landing-actions {
  animation: mc-copy-in 0.6s cubic-bezier(0.22, 1, 0.36, 1) 0.52s backwards;
}
.landing-proof .landing-stat:nth-child(1) {
  animation: mc-stat-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.6s backwards;
}
.landing-proof .landing-stat:nth-child(2) {
  animation: mc-stat-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.7s backwards;
}
.landing-proof .landing-stat:nth-child(3) {
  animation: mc-stat-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.8s backwards;
}

/* The hero problem card swings in through 3D space (perspective comes
   from .landing-visual below). "backwards" + ending exactly at the
   app's own rotate(1.6deg) rest pose means the tilt engine can take
   over the transform the instant this finishes. */
.landing-visual .arena-preview {
  animation: mc-preview-swing 0.9s cubic-bezier(0.22, 1, 0.36, 1) 0.22s backwards;
}
.landing-visual .preview-orbit-one {
  animation: mc-orbit-in-1 0.85s ease 0.3s backwards;
}
.landing-visual .preview-orbit-two {
  animation: mc-orbit-in-2 0.85s ease 0.4s backwards;
}
.landing-visual .preview-float-top {
  animation:
    mc-float-in 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) 0.62s backwards,
    mc-bob-a 4.6s ease-in-out 1.4s infinite alternate;
}
.landing-visual .preview-float-bottom {
  animation:
    mc-float-in 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) 0.74s backwards,
    mc-bob-b 5.4s ease-in-out 1.7s infinite alternate;
}

/* Feature chips flip in, then tilt toward the hovered corner via the
   individual `rotate` property (polish.js sets --frx / --fry) — this
   composes with the app's own transform hover-lift, and the transition
   list mirrors the app's so nothing it animates is lost. */
.landing-features .landing-feature:nth-child(1) {
  animation: mc-feat-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.5s backwards;
}
.landing-features .landing-feature:nth-child(2) {
  animation: mc-feat-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.62s backwards;
}
.landing-features .landing-feature:nth-child(3) {
  animation: mc-feat-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.74s backwards;
}
.landing-features { perspective: 900px; }
/* Feature tilt via transform custom props (polish.js sets --frx/--fry).
   The hover rule re-states the app's own -2px lift alongside the tilt,
   so the app's hover behavior is reproduced exactly, not lost. */
.landing-feature {
  transform: rotateX(var(--frx, 0deg)) rotateY(var(--fry, 0deg));
  transition: transform 0.18s ease-out,
              border-color 0.2s,
              background 0.2s;
}
.landing-feature:hover {
  transform: rotateX(var(--frx, 0deg)) rotateY(var(--fry, 0deg)) translateY(-2px);
}

@keyframes mc-h1-wipe {
  from { opacity: 0; clip-path: inset(0 100% 0 0); transform: translateY(18px); }
  to   { opacity: 1; clip-path: inset(0 0 0 0);    transform: none; }
}
@keyframes mc-copy-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
@keyframes mc-stat-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@keyframes mc-preview-swing {
  from { opacity: 0; transform: rotateY(16deg) rotateZ(4deg) translateY(30px) scale(0.94); }
  to   { opacity: 1; transform: rotateZ(1.6deg); }
}
@keyframes mc-orbit-in-1 {
  from { opacity: 0; transform: rotate(-22deg) scale(0.7); }
  to   { opacity: 1; transform: rotate(-22deg) scale(1); }
}
@keyframes mc-orbit-in-2 {
  from { opacity: 0; transform: rotate(37deg) scale(0.7); }
  to   { opacity: 1; transform: rotate(37deg) scale(1); }
}
@keyframes mc-float-in {
  from { opacity: 0; scale: 0.6; }
  to   { opacity: 1; scale: 1; }
}
@keyframes mc-bob-a {
  from { transform: translateY(0); }
  to   { transform: translateY(-6px); }
}
@keyframes mc-bob-b {
  from { transform: translateY(0); }
  to   { transform: translateY(5px); }
}
@keyframes mc-feat-in {
  from { opacity: 0; transform: translateY(14px) rotateX(10deg) scale(0.97); }
  to   { opacity: 1; transform: none; }
}

/* ---------- 22. v10 TILT CARD: perspective space, glare, depth -------
   (engine in polish.js: pointer-enter/move/leave on .arena-preview,
   spring-lerped in one rAF loop that releases all inline styles the
   moment it settles.) */
.landing-visual { perspective: 1100px; }

.arena-preview.mc-3d {
  transform-style: preserve-3d;
  will-change: transform;
}
/* Inner sections sit at different depths, so the tilt reads as volume
   rather than a flat plane. None of these have app transforms. */
.arena-preview .preview-header  { transform: translateZ(16px); }
.arena-preview .preview-meta    { transform: translateZ(16px); }
.arena-preview .preview-question{ transform: translateZ(26px); }
.arena-preview .preview-divider { transform: translateZ(18px); }
.arena-preview .preview-answer  { transform: translateZ(34px); }
.arena-preview .preview-footer  { transform: translateZ(12px); }
.arena-preview .preview-progress{ transform: translateZ(20px); }

/* Cursor-tracking glare (child appended by polish.js; --gx / --gy are
   set from the same spring as the tilt, so the light lags exactly as
   gracefully as the card leans). */
.mc-glare {
  position: absolute;
  left: var(--gx, 50%);
  top: var(--gy, 50%);
  width: 300px;
  height: 300px;
  border-radius: 999px;
  transform: translate(-50%, -50%);
  background: radial-gradient(
    circle,
    rgba(180, 246, 241, 0.13),
    rgba(180, 246, 241, 0.04) 45%,
    transparent 65%
  );
  opacity: 0;
  transition: opacity 0.35s ease;
  pointer-events: none;
  z-index: 4;
}
.arena-preview.mc-3d:hover .mc-glare { opacity: 1; }

/* ---------- 23. v10 CUSTOM CURSOR (landing + auth only) --------------
   Mounted/unmounted by polish.js together with the mc-cursor-on class
   on <html>. The native caret cursor stays available on auth inputs;
   everywhere else on these two presentation surfaces the mint dot +
   spring ring take over. */
@media (pointer: fine) {
  html.mc-cursor-on .landing-screen,
  html.mc-cursor-on .auth-screen,
  html.mc-cursor-on .landing-screen *,
  html.mc-cursor-on .auth-screen * { cursor: none; }
  html.mc-cursor-on .auth-screen input,
  html.mc-cursor-on .auth-screen textarea,
  html.mc-cursor-on .auth-screen select { cursor: auto; }
}
#mc-cursor-dot {
  position: fixed;
  top: -3px;
  left: -3px;
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: #b4f6f1;
  z-index: 10001;
  pointer-events: none;
  will-change: transform;
  box-shadow: 0 0 10px rgba(180, 246, 241, 0.8);
  transition: opacity 0.25s ease, scale 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}
#mc-cursor-dot[data-text="1"] { scale: 0; }
#mc-cursor-ring {
  position: fixed;
  top: -20px;
  left: -20px;
  width: 40px;
  height: 40px;
  z-index: 10000;
  pointer-events: none;
  will-change: transform;
}
#mc-cursor-ring i {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 999px;
  border: 1.5px solid rgba(180, 246, 241, 0.5);
  transition:
    transform 0.35s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.25s ease,
    background-color 0.35s ease,
    border-color 0.35s ease;
}
#mc-cursor-ring[data-variant="hover"] i {
  transform: scale(1.6);
  background-color: rgba(103, 213, 172, 0.12);
  border-color: rgba(103, 213, 172, 0.9);
}
#mc-cursor-ring[data-variant="text"] i {
  opacity: 0;
  transform: scale(0.5);
}

/* ---------- 24. v10 FILM GRAIN (delivery-site texture) ---------------- */
#mc-grain {
  position: fixed;
  inset: -120px;
  z-index: 75;
  pointer-events: none;
  opacity: 0.04;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.7' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23g)'/%3E%3C/svg%3E");
  background-size: 240px 240px;
  animation: mc-grain-shift 0.85s steps(6) infinite;
}
@keyframes mc-grain-shift {
  0%   { transform: translate(0, 0); }
  20%  { transform: translate(-34px, 22px); }
  40%  { transform: translate(22px, -38px); }
  60%  { transform: translate(-28px, -22px); }
  80%  { transform: translate(34px, 28px); }
  100% { transform: translate(0, 0); }
}

/* ---------- 14b. v11 slide keyframes (tab transitions) --------------
   Flat translateX + opacity only: every frame stays axis-aligned so
   the browser never has to rasterize tilted text. */
@keyframes mc-card-slide-fwd {
  from { opacity: 0; transform: translateX(-34px); }
  to   { opacity: 1; transform: none; }
}
@keyframes mc-card-slide-back {
  from { opacity: 0; transform: translateX(34px); }
  to   { opacity: 1; transform: none; }
}
@keyframes mc-ghost-slide-fwd {
  to { opacity: 0; transform: translateX(-72px); }
}
@keyframes mc-ghost-slide-back {
  to { opacity: 0; transform: translateX(72px); }
}

/* ---------- 25. v11 INTERIOR — living decor for the game shell ------
   All of it is additive decoration for LOBBY surfaces only: nothing
   mounts inside .problem-card, and the ticker fades itself out while
   a play surface is the active panel. Chips + icons are injected by
   polish.js (idempotent, re-wired through scan()); the rails and
   ticker are body-level fixed nodes that live only while the app
   shell is mounted. */

/* Mint icon chip next to panel titles. */
.mc-tchip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  margin-right: 8px;
  border-radius: 8px;
  background: rgba(103, 213, 172, 0.09);
  border: 1px solid rgba(103, 213, 172, 0.22);
  color: #67d5ac;
  vertical-align: -6px;
  flex: none;
}
.mc-tchip svg { display: block; }
/* The app's .lb-header h2 is display:flex (gap 9px) — let it space. */
.lb-header h2 .mc-tchip { margin-right: 0; }

/* Mini icons inside the tab strip and the 1v1/2v2 + Create/Join
   toggles. Vertical-align keeps the label baseline unchanged.
   v13: phones keep the icons too — a compact 10px form with a tight
   margin, instead of the old ≤560px display:none that made the strip
   icon-less exactly where icons read best. */
.mc-tab-ic {
  display: inline-flex;
  vertical-align: -2px;
  margin-right: 6px;
  opacity: 0.8;
  color: currentColor;
}
.mc-tab-ic svg { display: block; }
.mode-tab .mc-tab-ic { opacity: 0.7; }
.mode-tab.active .mc-tab-ic { opacity: 1; }
.duel-kind-btn .mc-tab-ic { margin-right: 7px; }
@media (max-width: 560px) {
  .mode-tab .mc-tab-ic { margin-right: 3px; vertical-align: -1px; }
  .mode-tab .mc-tab-ic svg { width: 10px; height: 10px; }
  .duel-kind-btn .mc-tab-ic svg { width: 11px; height: 11px; }
}
/* The one band where the icons cannot pay rent: at 881–1160px the app
   is two-column and the five tabs shrink to ~105px — "Leaderboard"
   alone is 92px, so even a 10px icon pushes the label into a visible
   clip (the app already clips ~3px natively there). Labels win; the
   icons return on both sides of the band (single-column ≥881px never
   happens below 881 — the 1-col grid and the wide 2-col layout both
   have room). The 1v1/2v2 + Create/Join toggle icons live in wide
   cards and stay visible at every width. */
@media (min-width: 881px) and (max-width: 1160px) {
  .mode-tab .mc-tab-ic { display: none; }
}

/* Corner brackets on lobby cards (class via polish.js).
   v12: :where() keeps this at ZERO specificity — the app styles several
   decorated cards with their own positioning (.leaderboard-card is
   position:sticky; top:91px on desktop). A plain .mc-deco{position:relative}
   loaded after the app CSS used to win that fight, turning the sticky
   offset into a RELATIVE +91px shift: the side leaderboard slid down and
   its last rows ended up underneath the focus card below. With :where(),
   any app position rule always wins, and cards the app leaves static
   still get relative for the brackets to anchor against. */
:where(.mc-deco) { position: relative; }
.mc-deco::before,
.mc-deco::after {
  content: "";
  position: absolute;
  width: 20px;
  height: 20px;
  pointer-events: none;
  opacity: 0.75;
  border: 0 solid rgba(103, 213, 172, 0.32);
  transition: border-color 0.3s ease, opacity 0.3s ease;
}
.mc-deco::before {
  top: 9px;
  left: 9px;
  border-top-width: 1.5px;
  border-left-width: 1.5px;
  border-top-left-radius: 7px;
}
.mc-deco::after {
  bottom: 9px;
  right: 9px;
  border-bottom-width: 1.5px;
  border-right-width: 1.5px;
  border-bottom-right-radius: 7px;
}
.mc-deco:hover::before,
.mc-deco:hover::after {
  border-color: rgba(180, 246, 241, 0.6);
  opacity: 1;
}

/* Watermark emblem inside lobby cards (div via polish.js). The
   wrapper clips the oversized glyph to the card bounds. */
.mc-emblem {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}
.mc-emblem i {
  position: absolute;
  top: -16px;
  right: -12px;
  display: block;
  width: 150px;
  height: 150px;
  color: #b4f6f1;
  opacity: 0.055;
  transform: rotate(-8deg);
}
.mc-emblem svg { width: 100%; height: 100%; display: block; }

/* Rotating flavor ticker (body-level, polish.js mounts it with the
   app shell). Fades out while the active panel shows a play surface
   (.mc-tick-hidden) and on phones, where space is scarce. */
#mc-ticker {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  pointer-events: none;
  z-index: 4;
  color: #67d5ac;
  opacity: 0.7;
  transition: opacity 0.5s ease;
}
#mc-ticker svg { flex: none; }
#mc-ticker span {
  font: 700 0.62rem var(--font-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(180, 246, 241, 0.55);
  white-space: nowrap;
  max-width: 82vw;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: opacity 0.42s ease, transform 0.42s ease;
}
#mc-ticker span.mc-tick-out {
  opacity: 0;
  transform: translateY(4px);
}
#mc-ticker.mc-tick-hidden { opacity: 0; }
@media (max-width: 640px) {
  #mc-ticker { display: none; }
}

/* Floating math glyphs along the screen edges (body-level, via
   polish.js; they live only while the app shell is mounted).
   v13 — THREE TIERS, so "the math formulas on the sides" exist at every
   viewport instead of only on ≥1500px monitors:
     • phones  (<760px):  whisper pair of glyphs per edge, sized to
       live inside the app's own 13px page padding — zero layout
       impact, pointer-events none;
     • tablets (≥760px):  slim 3-glyph strips in the 22px side
       padding the app reserves at that width;
     • desktops (≥1360px): the full 5-glyph rails + MATHCLASH label,
       centered in the real content gutters ((100vw - 1240px) / 2 per
       side — the app's own max column width). */
#mc-rail-l,
#mc-rail-r {
  position: fixed;
  top: 0;
  bottom: 0;
  width: 13px;
  left: 0;
  display: block;
  pointer-events: none;
  z-index: 2;
  color: #b4f6f1;
}
#mc-rail-r { left: auto; right: 0; }
#mc-rail-l i,
#mc-rail-r i {
  position: absolute;
  left: 0;
  right: 0;
  text-align: center;
  font-family: var(--font-mono);
  font-weight: 700;
  color: rgba(180, 246, 241, 0.13);
  animation: mc-rail-float 8.5s ease-in-out infinite alternate;
}
/* Phone tier — three whisper glyphs per edge, sized to sit inside the
   app's 13px page padding. v13.1: raised from two glyphs at 0.24–0.30
   alpha — at that level they were invisible on phones; three glyphs
   at ~0.5 read as a deliberate edge watermark without crowding the
   13px the app reserves. */
#mc-rail-l i:nth-child(1) { top: 9%;  font-size: 11px; color: rgba(103, 213, 172, 0.52); }
#mc-rail-l i:nth-child(2) { top: 48%; font-size: 10px; color: rgba(180, 246, 241, 0.44); animation-delay: -3.4s; }
#mc-rail-l i:nth-child(3) { top: 87%; font-size: 11px; color: rgba(103, 213, 172, 0.48); animation-delay: -4.8s; }
#mc-rail-r i:nth-child(1) { top: 13%; font-size: 10px; color: rgba(180, 246, 241, 0.44); animation-delay: -1.8s; }
#mc-rail-r i:nth-child(2) { top: 52%; font-size: 11px; color: rgba(103, 213, 172, 0.52); animation-delay: -2.6s; }
#mc-rail-r i:nth-child(3) { top: 90%; font-size: 10px; color: rgba(180, 246, 241, 0.44); animation-delay: -5.1s; }
#mc-rail-l i:nth-child(n+4),
#mc-rail-r i:nth-child(n+4),
#mc-rail-r b { display: none; }

@keyframes mc-rail-float {
  from { transform: translateY(-9px); }
  to   { transform: translateY(9px); }
}

/* Tablet tier — slim three-glyph strips in the app's 22px side
   padding (the app is single-column ≤880px, two-column with filled
   width up to 1240px; either way those 22px are empty). */
@media (min-width: 760px) {
  #mc-rail-l,
  #mc-rail-r { width: 22px; }
  #mc-rail-l i:nth-child(n+3),
  #mc-rail-r i:nth-child(n+3) { display: block; }
  #mc-rail-l i:nth-child(1) { top: 14%; font-size: 17px; color: rgba(103, 213, 172, 0.34); }
  #mc-rail-l i:nth-child(2) { top: 50%; font-size: 14px; color: rgba(180, 246, 241, 0.30); animation-delay: -2.2s; }
  #mc-rail-l i:nth-child(3) { top: 84%; font-size: 18px; color: rgba(103, 213, 172, 0.30); animation-delay: -4.1s; }
  #mc-rail-r i:nth-child(1) { top: 22%; font-size: 16px; color: rgba(180, 246, 241, 0.30); animation-delay: -3s; }
  #mc-rail-r i:nth-child(2) { top: 56%; font-size: 14px; color: rgba(103, 213, 172, 0.34); animation-delay: -0.9s; }
  #mc-rail-r i:nth-child(3) { top: 88%; font-size: 17px; color: rgba(103, 213, 172, 0.30); animation-delay: -4.6s; }
  #mc-rail-l i:nth-child(n+4),
  #mc-rail-r i:nth-child(n+4) { display: none; }
}

/* Desktop tier — the full rails, centered in the real content gutters:
   the app column is min(1240px, 100%), so from 1360px each gutter is
   at least 60px wide and a 44px rail sits comfortably inside. */
@media (min-width: 1360px) {
  #mc-rail-l,
  #mc-rail-r { width: 44px; }
  #mc-rail-l { left: calc((100vw - 1240px) / 2 - 48px); }
  #mc-rail-r { right: calc((100vw - 1240px) / 2 - 48px); }
  #mc-rail-l i:nth-child(n+4),
  #mc-rail-r i:nth-child(n+4) { display: block; }
  #mc-rail-l i:nth-child(1) { top: 16%; font-size: 26px; color: rgba(103, 213, 172, 0.20); }
  #mc-rail-l i:nth-child(2) { top: 33%; font-size: 17px; animation-delay: -2.2s; animation-duration: 10s; }
  #mc-rail-l i:nth-child(3) { top: 50%; font-size: 30px; color: rgba(103, 213, 172, 0.16); animation-delay: -4.1s; animation-duration: 9.2s; }
  #mc-rail-l i:nth-child(4) { top: 67%; font-size: 15px; animation-delay: -1.4s; }
  #mc-rail-l i:nth-child(5) { top: 83%; font-size: 22px; color: rgba(103, 213, 172, 0.18); animation-delay: -5.8s; animation-duration: 11s; }
  #mc-rail-r i:nth-child(1) { top: 20%; font-size: 24px; color: rgba(103, 213, 172, 0.18); animation-delay: -3s; }
  #mc-rail-r i:nth-child(2) { top: 37%; font-size: 16px; animation-delay: -0.9s; animation-duration: 9.6s; }
  #mc-rail-r i:nth-child(3) { top: 54%; font-size: 28px; color: rgba(180, 246, 241, 0.15); animation-delay: -4.6s; }
  #mc-rail-r i:nth-child(4) { top: 71%; font-size: 14px; animation-delay: -2.7s; animation-duration: 10.4s; }
  #mc-rail-r i:nth-child(5) { top: 86%; font-size: 20px; color: rgba(103, 213, 172, 0.20); animation-delay: -6.2s; }
  #mc-rail-r b {
    display: block;
    position: absolute;
    top: 26px;
    right: 13px;
    writing-mode: vertical-rl;
    font: 700 0.6rem var(--font-mono);
    letter-spacing: 0.42em;
    text-transform: uppercase;
    color: rgba(180, 246, 241, 0.22);
  }
}

/* ---------- 20. Global kill-switch ---------- */
@media (prefers-reduced-motion: reduce) {
  .app-shell,
  .auth-page-content,
  .landing-screen,
  .info-screen,
  .navbar,
  .landing-screen .landing-shell > *,
  .auth-layout > *,
  #mc-sweep i,
  #mc-aurora i,
  .card,
  .btn,
  .mode-selector-indicator,
  .mode-tab,
  .feedback,
  .feedback.err,
  .timer.mc-urgent,
  .problem-copy.mc-fresh,
  .lb-table tbody tr,
  .party-roster .party-player,
  .party-standings .party-row,
  .party-podium .party-step,
  .party-podium .party-step-bar span,
  .party-podium .party-step.place-1 .party-step-bar,
  .duel-end-banner.mc-victory,
  h2.duel-title.mc-victory,
  .duel-end-banner.mc-defeat,
  .duel-end-banner.mc-draw,
  .mc-screen-in,
  .mc-panel-enter > *,
  .mc-ghost,
  .duel-ready,
  .mc-pop-num,
  .mc-num-down,
  .mc-pip-in,
  .mc-press,
  .streak-badge .streak-flame,
  .streak-badge.mc-streak-hot,
  .streak-badge.mc-streak-hot .streak-flame,
  #mc-milestone .mcs-dim,
  #mc-milestone .mcs-ring,
  #mc-milestone .mcs-edge,
  #mc-milestone .mcs-banner,
  #mc-milestone[data-tier="100"] .mcs-word,
  .landing-copy .eyebrow,
  .landing-copy h1,
  .landing-copy .landing-tagline,
  .landing-copy .landing-audience,
  .landing-copy .landing-actions,
  .landing-proof .landing-stat,
  .landing-visual .arena-preview,
  .landing-visual .preview-orbit-one,
  .landing-visual .preview-orbit-two,
  .landing-visual .preview-float-top,
  .landing-visual .preview-float-bottom,
  .landing-features .landing-feature,
  .mc-glare,
  #mc-grain,
  #mc-rail-l i,
  #mc-rail-r i,
  #mc-ticker,
  #mc-ticker span,
  .mc-deco::before,
  .mc-deco::after {
    animation: none !important;
    transition: none !important;
  }
  /* Under reduced motion the JS engines for animated layers never run,
     so these are belt-and-braces: static grain hidden entirely (grain
     IS the animation), glare off, feature tilt neutralized. v13: the
     rails + ticker are NO LONGER hidden here — their float / crossfade
     is frozen by the block above, but the glyphs and the flavor line
     are static art. "Reduce motion" calms the room; it does not strip
     it bare (that was v12's bug: every chip, icon, bracket, rail and
     the ticker vanished on reduce-motion devices, reading exactly like
     "the icons, the math formulas and the rounded corners were
     removed"). */
  #mc-grain { display: none; }
  .mc-glare { opacity: 0; }
  .landing-feature { transform: none; }
  .lb-table tbody tr:nth-child(1) .rank::after {
    animation: none !important;
    opacity: 0;
  }
  .lb-table tbody tr:nth-child(1) .rank::before,
  .lb-table tbody tr:nth-child(2) .rank::before,
  .lb-table tbody tr:nth-child(3) .rank::before {
    transition: none !important;
  }
  .card:hover { transform: none; }
  .btn:hover:not(:disabled) { transform: none; }
  .btn:active:not(:disabled) { transform: none; }
}

/* Round 17: custom cursor stays hidden until the mouse has really moved
   (it used to sit at the top-left corner on first paint). */
html:not(.mc-cursor-live) #mc-cursor-dot,
html:not(.mc-cursor-live) #mc-cursor-ring { opacity: 0 !important; }
