  :root {
    --bg: #141d33; --panel: #1d2845; --grid: #2b3a5e; --line: #5ad1f0;
    --text: #eef2fb; --muted: #9fb0d0; --green: #3ad884; --red: #ff6b81; --gold: #ffd166;
  }
  * { box-sizing: border-box; }
  html, body { margin: 0; min-height: 100%; background: var(--bg); color: var(--text);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    /* clip (not hidden) contains horizontal overflow WITHOUT forcing overflow-y to auto — that gotcha made html+body
       nested scroll containers, which breaks touch scrolling on Android. clip keeps overflow-y visible → native window scroll. */
    overflow-x: clip; overscroll-behavior-x: none; }
  .wrap { max-width: 100%; margin: 0 auto; padding: 22px 20px 40px; overflow-x: clip; }
  @media (min-width: 1041px) { .wrap { max-width: 1040px; } }
  h1 { font-size: 22px; margin: 0; letter-spacing: 1px; }
  h1 small { color: var(--muted); font-weight: 400; font-size: 13px; margin-left: 8px; letter-spacing: 0; }
  .pos { color: var(--green); } .neg { color: var(--red); } .gold { color: var(--gold); }
  button { font-family: inherit; cursor: pointer; }
  kbd { background: var(--grid); border-radius: 6px; padding: 2px 9px; color: var(--text); border: 1px solid #2c3a56; }

  /* ---------- LEVEL SELECT ---------- */
  .lead { color: var(--muted); margin: 8px 0 16px; font-size: 15px; }

  /* hero header — trading-terminal look */
  .hero { position: relative; margin: 0 0 18px; padding: 22px; border-radius: 18px; overflow: hidden;
    background-color: #0a1322;
    background-image: linear-gradient(rgba(90,209,240,.05) 1px, transparent 1px), linear-gradient(90deg, rgba(90,209,240,.05) 1px, transparent 1px);
    background-size: 30px 30px; border: 1px solid var(--grid); }
  .hero::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px; background: linear-gradient(90deg, var(--line), var(--green)); }

  .brand { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
  .brandL { display: flex; align-items: center; gap: 12px; }
  .brand .logo { display: flex; }
  .wordmark { font: 900 34px/1 ui-sans-serif, system-ui, -apple-system, sans-serif; letter-spacing: 2px; margin: 0; color: var(--text);
    text-shadow: 0 0 22px rgba(90,209,240,.30); }
  .live { display: inline-flex; align-items: center; gap: 6px; font: 700 11px ui-monospace, Menlo, monospace; letter-spacing: 1.5px;
    color: var(--green); border: 1px solid rgba(58,216,132,.45); border-radius: 7px; padding: 4px 9px; }
  .live .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--green); box-shadow: 0 0 9px var(--green); animation: pulse 1.5s infinite; }
  @keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .3; } }
  .tagline { color: var(--text); opacity: .8; font-size: 15px; margin: 13px 0 16px; max-width: 640px; }
  /* lobby hook — the pitch, surfaced where players land (not just the <title>) */
  .lobbyhook { text-align: center; font: 800 clamp(19px, 5.4vw, 28px)/1.18 ui-sans-serif, system-ui, sans-serif;
    letter-spacing: -.3px; margin: 2px 0 16px; color: var(--text); text-wrap: balance; }
  .lobbyhook b { color: var(--green); font-weight: 800; }
  .lobbyhook i { color: var(--red); font-style: normal; font-weight: 800; }
  /* lobby legal strip + footer — unobtrusive (disclaimer, 13+, Privacy/Terms links) */
  .lobbydisc { text-align: center; font-size: 11.5px; color: var(--muted); margin: -8px 0 14px; letter-spacing: .2px; opacity: .85; }
  .legalfoot { text-align: center; margin: 26px 0 6px; padding-top: 16px; border-top: 1px solid var(--grid); color: var(--muted); font-size: 11.5px; line-height: 1.7; }
  .legalfoot a { color: var(--muted); text-decoration: none; border-bottom: 1px solid var(--grid); }
  .legalfoot a:hover { color: var(--line); }
  /* E1: "formerly Top Ticking" — a quiet line while the rename beds in (toggled by SHOW_FORMERLY in config.js). */
  .legalfoot .lf-formerly { margin-top: 4px; font-size: 10.5px; letter-spacing: .3px; opacity: .6; font-style: italic; }
  .nextdaily { text-align: center; font-size: 12.5px; color: var(--muted); margin-top: 7px; letter-spacing: .2px; }
  .nextdaily b { color: var(--line); font-weight: 700; font-variant-numeric: tabular-nums; }
  .chips { display: flex; flex-wrap: wrap; gap: 8px; }
  .chip { background: rgba(255,255,255,.035); border: 1px solid var(--grid); border-radius: 8px;
    padding: 7px 12px; font: 600 12.5px ui-monospace, "SF Mono", Menlo, monospace; color: var(--muted); display: inline-flex; align-items: center; gap: 6px; }
  .chip kbd { padding: 1px 7px; font-size: 11px; }
  .chip.gold { color: var(--gold); border-color: rgba(252,191,73,.40); background: rgba(252,191,73,.07); }
  @media (max-width: 480px) { .wordmark { font-size: 28px; } .hero { padding: 18px; } }
  #search { width: 100%; margin: 0 0 10px; padding: 13px 16px; font-size: 16px; color: var(--text);
    background: var(--panel); border: 1px solid var(--grid); border-radius: 12px; outline: none; }
  #search:focus { border-color: var(--line); }
  #search::placeholder { color: var(--muted); }
  .secLabel { color: var(--muted); font-size: 12px; letter-spacing: .8px; text-transform: uppercase; margin: 18px 0 10px; }

  /* daily + campaign banners */
  .bigcard { background: linear-gradient(135deg, #19233a, #131c2e); border: 1px solid var(--line); border-radius: 20px; padding: 17px 19px; margin: 0 0 16px; }
  #campaignCard { border-color: rgba(252,191,73,.45); }
  .bigcard .dhead { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px; }
  .bigcard .dtitle { font-size: 16px; font-weight: 800; letter-spacing: .3px; }
  .bigcard .dtitle .em { font-size: 20px; }
  .bigcard .dsub { color: var(--muted); font-size: 13px; margin-top: 3px; }
  .dco { color: var(--text); opacity: .78; font-size: 12.5px; font-weight: 700; margin-top: 3px; }
  .daily-hero .dco { font-size: 13.5px; margin-top: 4px; }
  .bigcard .streak { font-weight: 800; color: var(--gold); }
  .bigcard button { background: var(--line); color: #06222e; border: 0; border-radius: 10px; padding: 10px 18px; font-weight: 800; min-height: 48px; text-align: center; line-height: 1.15; }
  .bigcard button.adbtn { background: var(--gold); }
  .bigcard .subbtn { font-size: 11px; font-weight: 600; opacity: .8; }
  .playcue { color: var(--line); font-weight: 800; font-size: 16px; white-space: nowrap; text-align: right; align-self: center; }
  .playcue .subbtn { display: block; color: var(--muted); opacity: 1; margin-top: 2px; }
  .bigcard .done { color: var(--green); font-weight: 800; }

  /* profile / ego strip */
  .profile { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; background: var(--panel); border: 1px solid var(--grid); border-radius: 14px; padding: 12px 16px; margin: 0 0 16px; }
  .profile .pl { display: flex; align-items: center; gap: 11px; }
  .profile .rkem { font-size: 30px; line-height: 1; }
  .profile .rkname { font-weight: 800; font-size: 16px; }
  .profile .rksub { color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: .5px; }
  .profile .rating { margin-left: auto; font-weight: 900; font-size: 26px; font-variant-numeric: tabular-nums; }
  .profile .rating span { color: var(--gold); font-size: 16px; margin-left: 2px; }
  .profile .pstats { width: 100%; color: var(--muted); font-size: 13px; border-top: 1px solid var(--grid); padding-top: 10px; }
  .profile .pstats b { color: var(--text); }
  .settings { width: 100%; border-top: 1px solid var(--grid); margin-top: 12px; padding-top: 6px; }
  .setrow { display: flex; align-items: center; justify-content: space-between; padding: 9px 0; font-size: 14px; font-weight: 600; color: var(--text); }
  .tgl { border: 0; border-radius: 999px; padding: 6px 18px; min-height: 34px; font-weight: 800; font-size: 13px; cursor: pointer; }
  .tgl.on { background: var(--green); color: #06251a; }
  .tgl.off { background: var(--grid); color: var(--muted); }
  .setrow.disabled { opacity: .45; }
  .setrow.disabled .tgl { cursor: default; }
  .setnote { color: var(--muted); font-size: 11px; font-weight: 600; margin-left: 7px; }
  .account { width: 100%; border-top: 1px solid var(--grid); margin-top: 12px; padding-top: 12px; }
  .account .accttitle { font-size: 14px; font-weight: 800; color: var(--text); }
  .account .acctnote { font-size: 12px; color: var(--muted); margin: 4px 0 10px; line-height: 1.4; }
  .account .acctin { font-size: 14px; color: var(--text); margin-bottom: 10px; }
  .acctinput { width: 100%; box-sizing: border-box; background: var(--bg); border: 1px solid var(--grid); border-radius: 10px; padding: 11px 13px; color: var(--text); font-size: 16px; margin-bottom: 9px; }
  .acctinput:focus { outline: none; border-color: var(--line); }
  .acctrow { display: flex; gap: 9px; }
  .acctbtn { flex: 1; border: 0; border-radius: 10px; min-height: 44px; font-weight: 800; font-size: 14px; cursor: pointer; background: var(--line); color: #06222e; }
  .acctbtn.ghost { background: var(--panel); color: var(--text); border: 1px solid var(--grid); }
  .acctbtn:disabled { opacity: .6; cursor: default; }
  #ratingLine { margin-top: 14px; font-weight: 800; font-size: 15px; }
  #ratingLine .up { color: var(--green); } #ratingLine .dn { color: var(--red); }

  /* tabbed app shell */
  .apptop { display: flex; align-items: center; justify-content: space-between; padding: 4px 0 12px; }
  .brand-mini { display: flex; align-items: center; gap: 9px; }
  .wordmark-mini { font-weight: 900; letter-spacing: 1.4px; font-size: 19px; }
  .topright { display: flex; align-items: center; gap: 8px; min-width: 0; }
  .acctchip { display: inline-flex; align-items: center; gap: 5px; max-width: 160px; min-height: 34px; border: 1px solid var(--grid); background: var(--panel); color: var(--text); border-radius: 999px; padding: 5px 11px; font-size: 13px; font-weight: 800; cursor: pointer; overflow: hidden; }
  .acctchip b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .acctchip.in { border-color: var(--green); }
  .infobtn { width: 34px; height: 34px; flex-shrink: 0; border-radius: 50%; background: var(--panel); border: 1px solid var(--grid);
    color: var(--muted); font: 900 17px Georgia, serif; font-style: italic; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
  .infobtn:hover { color: var(--text); border-color: var(--line); }
  /* guided spotlight tour */
  /* BUG-06: the guided-tour overlay is styled by its #coach id, NOT the .coach class — the in-run chart coach
     (further down) is ALSO .coach and set pointer-events:none + a transform + z-index:8, which was bleeding onto
     this overlay and making Next/Skip unclickable on a tour replay. */
  #coach { position: fixed; inset: 0; z-index: 90; pointer-events: auto; transform: none; }
  #coach.hidden { display: none; }
  .coachhole { position: absolute; border-radius: 16px; box-shadow: 0 0 0 9999px rgba(8,12,22,.76); transition: all .25s ease; }
  .coachtip { position: absolute; max-width: 300px; background: var(--panel); border: 1px solid var(--line); border-radius: 16px; padding: 14px 16px;
    box-shadow: 0 14px 44px rgba(0,0,0,.55); transition: top .2s ease, left .2s ease; }
  .coachtip #coachText { font-size: 14.5px; line-height: 1.45; color: var(--text); }
  .coachtip #coachText b { color: var(--line); }
  .coachnav { display: flex; align-items: center; gap: 10px; margin-top: 13px; }
  .coachstepn { font-size: 12px; color: var(--muted); margin-right: auto; font-weight: 700; font-variant-numeric: tabular-nums; }
  .coachskip { background: none; border: 0; color: var(--muted); font-size: 13px; cursor: pointer; padding: 4px; }
  .coachnext { background: var(--line); color: #06222e; border: 0; border-radius: 11px; padding: 9px 18px; font-weight: 900; cursor: pointer; min-height: 40px; }
  .rankchip { display: inline-flex; align-items: center; gap: 6px; background: var(--panel); border: 1px solid var(--grid);
    border-radius: 999px; padding: 7px 13px; color: var(--text); cursor: pointer; min-height: 38px; min-width: 0; max-width: 100%; overflow: hidden; }
  .rankchip .rkemoji { font-size: 16px; line-height: 1; flex-shrink: 0; }
  .rankchip .rktitle { font-weight: 800; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .rankchip .rklvl { color: var(--muted); font-weight: 700; font-size: 14px; padding-left: 7px; border-left: 1px solid var(--grid); white-space: nowrap; flex-shrink: 0; }
  .tabpanel { padding-bottom: 24px; }
  /* "scroll for more" nudge — shows when lobby content runs below the fold (mostly mobile) */
  .scrollHint { position: fixed; left: 50%; transform: translateX(-50%); bottom: calc(76px + env(safe-area-inset-bottom)); z-index: 35;
    display: inline-flex; align-items: center; gap: 6px; padding: 7px 15px; border-radius: 999px;
    background: var(--line); color: #06222e; font-weight: 800; font-size: 12.5px; box-shadow: 0 6px 20px rgba(0,0,0,.4);
    border: 0; cursor: pointer; pointer-events: auto; font-family: inherit; appearance: none; -webkit-appearance: none;
    -webkit-tap-highlight-color: transparent; animation: hintbob 1.5s ease-in-out infinite; }
  .scrollHint:active { transform: translateX(-50%) translateY(2px); }
  .scrollHint .chev { font-size: 16px; line-height: 1; }
  .scrollHint.hidden { display: none; }
  @keyframes hintbob { 0%,100% { transform: translateX(-50%) translateY(0); } 50% { transform: translateX(-50%) translateY(5px); } }
  /* always-on-top resources */
  #resourceBar { position: sticky; top: 0; z-index: 30; display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
    padding: 8px 0 8px; margin: 0 0 6px; background: var(--bg); }
  .statgroup { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 8px; }
  .rchip { display: inline-flex; align-items: center; gap: 6px; background: var(--panel); border: 1px solid var(--grid);
    border-radius: 999px; padding: 7px 13px; color: var(--text); font-weight: 800; font-size: 15px; cursor: pointer;
    font-variant-numeric: tabular-nums; min-height: 38px; }
  .rchip .ri { font-size: 15px; }
  .coin { display: inline-block; vertical-align: -0.16em; }
  .rchip .rtimer { color: var(--muted); font-weight: 600; font-size: 12px; margin-left: 2px; }
  #coinsChip { color: var(--gold); }
  .netchip { display: inline-flex; align-items: center; gap: 6px; background: var(--panel); border: 1px solid var(--grid);
    border-radius: 999px; padding: 7px 13px; min-height: 38px; cursor: pointer; font-variant-numeric: tabular-nums; }
  .netchip .nwlabel { color: var(--muted); font-size: 12.5px; font-weight: 700; }
  .netchip b { font-size: 19px; font-weight: 800; }
  #coinsChip .ri { filter: none; }
  /* desktop default: top tabs */
  .appnav { display: flex; gap: 4px; border-bottom: 1px solid var(--grid); margin: 6px 0 20px; }
  .appnav button { display: inline-flex; align-items: center; gap: 7px; background: transparent; border: 0; color: var(--muted);
    font-weight: 700; font-size: 14px; padding: 10px 16px; border-bottom: 2px solid transparent; min-height: auto; }
  .appnav button .ico { font-size: 16px; filter: grayscale(.3); }
  .appnav button.active { color: var(--text); border-bottom-color: var(--line); }
  .appnav button.active .ico { filter: none; }
  /* mobile: bottom bar */
  @media (max-width: 719px) {
    .apptop { padding-right: 0; }
    /* mobile: rank on its own top line, then net worth · lives · coins together below */
    #resourceBar { gap: 6px; padding: 7px 0 5px; }
    .statgroup { flex: 0 0 100%; gap: 6px; }
    .rankchip, .rchip { min-height: 32px; padding: 5px 10px; font-size: 13px; }
    .rankchip .rktitle { font-size: 12.5px; }
    .rankchip .rklvl { font-size: 12.5px; padding-left: 6px; }
    .rchip .rtimer { font-size: 10.5px; }
    .rankchip .rkemoji { font-size: 15px; }
    .netchip b { font-size: 19px; }
    .netchip .nwlabel { font-size: 11px; }
    .appnav { position: fixed; left: 0; right: 0; bottom: 0; z-index: 40; margin: 0; border-top: 1px solid var(--grid); border-bottom: 0;
      justify-content: center; background: rgba(11,18,32,.96); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
      padding: 6px 4px calc(6px + env(safe-area-inset-bottom)); }
    .appnav button { flex: 1; max-width: 130px; flex-direction: column; gap: 3px; font-size: 11px; padding: 6px 0; min-height: 54px; border-bottom: 0; }
    .appnav button.active { border-bottom: 0; }
    .appnav button .ico { font-size: 21px; }
    .wrap { padding-bottom: 0; }                 /* nav clearance is on .tabpanel; avoids dead scroll space */
    .tabpanel { padding-bottom: 78px; }          /* just clears the fixed bottom nav, no black gap below */
  }

  /* section headers + visual hierarchy */
  .secHead { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin: 24px 0 12px; }
  .tabpanel > .secHead:first-child, .playcol > .secHead:first-child { margin-top: 8px; }
  .playgrid { display: grid; gap: 4px 22px; }
  .playcol .secHead { margin-bottom: 12px; }
  @media (min-width: 760px) {
    .playgrid { grid-template-columns: 1fr 1fr; align-items: stretch; }
    .playcol { display: flex; flex-direction: column; }
    .playcol .bigcard { flex: 1; display: flex; flex-direction: column; justify-content: center; }
    .playcol #campaignCard { justify-content: flex-start; }
    .playcol #campaignCard .campprog { margin-top: auto; }
  }
  @media (min-width: 760px) { #tab-League, #tab-Profile { max-width: 660px; margin: 0 auto; } }
  .secHead > span:first-child { font-size: 17px; font-weight: 900; letter-spacing: .2px; }
  /* DAILY = hero: bigger + brighter */
  .daily-hero { padding: 19px 21px; border-color: var(--line); border-radius: 22px;
    background: radial-gradient(130% 170% at 100% 0%, rgba(90,209,240,.20), transparent 55%), linear-gradient(135deg, #243358, #1a2540);
    box-shadow: 0 0 0 1px rgba(90,209,240,.14), 0 10px 34px rgba(0,0,0,.28); }
  .daily-hero .dkicker { color: var(--line); font: 700 11px ui-monospace, Menlo, monospace; letter-spacing: 2px; }
  .daily-hero .dtitle { font-size: 24px; margin-top: 5px; }
  .dmut { margin-top: 11px; padding: 7px 11px; border-radius: 10px; background: rgba(252,191,73,.12); border: 1px solid rgba(252,191,73,.4); color: var(--text); font-size: 12.5px; font-weight: 600; }
  .dtheme { margin-top: 11px; padding: 7px 11px; border-radius: 10px; background: rgba(90,209,240,.10); border: 1px solid rgba(90,209,240,.32); color: var(--text); font-size: 12.5px; font-weight: 600; }
  .dtheme b { color: var(--line); }
  .dmut b { color: var(--gold); }
  .dsocial { margin-top: 12px; padding-top: 10px; border-top: 1px solid rgba(90,209,240,.18); color: var(--muted); font-size: 12.5px; font-weight: 600; }
  .dright { display: flex; align-items: center; gap: 18px; }
  .streakBig { text-align: center; font-size: 24px; font-weight: 900; color: var(--gold); line-height: 1; }
  .streakBig span { display: block; font-size: 10px; font-weight: 600; color: var(--muted); letter-spacing: .5px; margin-top: 4px; text-transform: uppercase; }
  /* DAILY MISSIONS */
  .mrow { display: flex; align-items: center; gap: 12px; padding: 11px 0; border-bottom: 1px solid var(--grid); }
  .mrow:last-child { border-bottom: 0; }
  .mleft { display: flex; align-items: center; gap: 11px; flex: 1; min-width: 0; }
  .memoji { font-size: 22px; flex-shrink: 0; }
  .mlabel { font-size: 13.5px; font-weight: 700; color: var(--text); }
  .mbar { height: 5px; background: var(--grid); border-radius: 99px; overflow: hidden; margin-top: 6px; max-width: 180px; }
  .mbar > div { height: 100%; background: linear-gradient(90deg, var(--line), var(--green)); transition: width .4s ease; }
  .maction { flex-shrink: 0; }
  .mprog { font-size: 12px; font-weight: 700; color: var(--muted); font-variant-numeric: tabular-nums; }
  .mclaimed { font-size: 12px; font-weight: 700; color: var(--green); }
  .bigcard .mclaim { display: inline-flex; align-items: center; gap: 5px; background: var(--gold); color: #1a1505; border: 0; border-radius: 10px; padding: 8px 13px; min-height: 0; font-size: 12.5px; font-weight: 800; cursor: pointer; }
  .bigcard .mclaim:active { transform: scale(.96); }
  .bigcard .crate { display: block; width: 100%; margin-top: 14px; padding: 14px; border-radius: 14px; border: 0; min-height: 0; cursor: pointer;
    font-size: 14.5px; font-weight: 800; color: #1a1505; background: linear-gradient(135deg, var(--gold), #ffb43d);
    box-shadow: 0 4px 18px rgba(255,209,102,.3); animation: cratepulse 1.4s ease-in-out infinite; }
  .bigcard .crate:active { transform: scale(.98); }
  .bigcard .crate.done { background: var(--panel); color: var(--muted); border: 1px solid var(--grid); box-shadow: none; animation: none; cursor: default; font-weight: 700; }
  @keyframes cratepulse { 0%,100% { box-shadow: 0 4px 18px rgba(255,209,102,.3); } 50% { box-shadow: 0 4px 26px rgba(255,209,102,.55); } }
  /* CAMPAIGN = demoted: quieter than the daily */
  .demoted { background: var(--panel); border-color: var(--grid); box-shadow: 0 6px 20px rgba(0,0,0,.22); padding: 18px 20px; }
  .demoted .dtitle { font-size: 16px; }
  .progress { height: 7px; background: var(--grid); border-radius: 99px; overflow: hidden; margin-top: 12px; }
  .campprog { display: flex; align-items: center; gap: 11px; margin-top: 12px; }
  .campprog .progress { flex: 1; margin-top: 0; }
  .campfrac { font-size: 12.5px; font-weight: 800; color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
  .progress > div { height: 100%; background: linear-gradient(90deg, var(--line), var(--green)); }
  /* Market Truth — educational stat callout above the boards */
  .markettruth { background: linear-gradient(135deg, #1d2b48, #182238); border: 1px solid var(--grid); border-radius: 14px;
    padding: 13px 16px; margin: 0 0 14px; }
  .markettruth .mthead { color: var(--gold); font: 800 11px ui-monospace, Menlo, monospace; letter-spacing: 1.6px; text-transform: uppercase; margin-bottom: 9px; }
  .markettruth .mtrow { color: var(--muted); font-size: 13.5px; line-height: 1.5; }
  .markettruth .mtrow b { color: var(--text); font-weight: 800; }
  .markettruth .mtwarm { color: var(--muted); font-size: 13px; }
  .subtabs { display: flex; gap: 6px; margin: 0 0 12px; }
  .subtabs button { background: var(--panel); border: 1px solid var(--grid); border-radius: 999px; padding: 7px 16px; color: var(--muted); font-weight: 700; font-size: 13px; }
  .subtabs button.active { background: var(--line); color: #06222e; border-color: var(--line); }
  .tyr { font-size: .62em; opacity: .72; margin-left: 3px; font-weight: 700; letter-spacing: 0; }
  /* pre-run briefing card: read the context before you choose a strategy */
  .bfname { display:flex; align-items:center; gap:8px; margin-bottom:9px; }
  .bfname .tpill { white-space: nowrap; flex: none; }   /* 375px: the year was breaking onto its own line */
  .bfname span { font-size: 15px; font-weight: 800; color: var(--text); }
  .bfhead { display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap; }
  .bfsec { font-size: 12px; font-weight: 800; color: var(--line); letter-spacing:.3px; text-transform: uppercase; }
  .bfvol { display:inline-flex; align-items:center; gap:5px; font-size:11px; color: var(--muted); }
  .bfvol b { color: var(--text); font-size: 11.5px; }
  .vseg { width: 13px; height: 5px; border-radius: 3px; background: var(--grid); display:inline-block; }
  .vseg.on.t0 { background:#3ad884; } .vseg.on.t1 { background:#5ad1f0; }
  .vseg.on.t2 { background:#ffd166; } .vseg.on.t3 { background:#ff6b81; }
  .bfera { margin-top:6px; font-size: 12.5px; color: var(--text); }
  .bfplay { margin-top:5px; font-size: 12px; color: var(--muted); line-height:1.35; }
  .bfplay b { color: var(--text); }
  .tgbox { max-width: 520px; max-height: 82vh; overflow-y: auto; text-align: left; }
  .tgrow { border: 1px solid var(--grid); border-radius: 12px; padding: 10px 12px; margin-bottom: 8px; background: var(--bg); text-align: left; }
  #tgList, .tgbox .adtag { text-align: left; }
  .tgrow.locked { opacity: .45; }
  .tghead { display: flex; align-items: center; gap: 8px; font-weight: 800; font-size: 14px; color: var(--text); }
  .tglock { margin-left: auto; font-size: 10.5px; color: var(--muted); font-weight: 700; }
  .tgbody { font-size: 12.5px; line-height: 1.5; color: var(--muted); margin-top: 7px; }
  .tghead[data-tg] { cursor: pointer; user-select: none; }
  .tgchev { margin-left: auto; color: var(--muted); font-size: 12px; }
  .tgrow { transition: border-color .15s; }
  .tgrow:has(.tgbody:not(.hidden)) { border-color: var(--line); }
  .tgbody b { color: var(--text); }
  /* post-run debrief — deliberately quiet: one coach line + one score pill. Detail lives under "Details". */
  #debrief { margin: 12px 0 2px; padding: 12px 14px; border: 1px solid var(--grid); border-radius: 14px; background: var(--bg); text-align: left; }
  #debrief:empty { display: none; }
  .dbcoach { font-size: 14px; line-height: 1.5; color: var(--text); }
  .dbfoot { display: flex; align-items: center; gap: 8px; margin-top: 9px; flex-wrap: wrap; }
  .dbpill { font-size: 11.5px; font-weight: 700; padding: 3px 9px; border-radius: 999px; border: 1px solid var(--grid); color: var(--muted); }
  .dbpill b { font-size: 13px; }
  .dbpill.good { color: var(--green); border-color: rgba(58,216,132,.4); }
  .dbpill.mid  { color: var(--gold);  border-color: rgba(255,209,102,.4); }
  .dbpill.poor { color: var(--red);   border-color: rgba(255,107,129,.4); }
  .dbhint { font-size: 11px; color: var(--muted); }
  .dbchips { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; margin: 4px 0 12px; }
  .dbchip { background: var(--panel); border: 1px solid var(--grid); border-radius: 10px; padding: 7px 4px; text-align: center; }
  .dbchip.bad { border-color: rgba(255,107,129,.55); background: rgba(255,107,129,.10); }
  .dbchip .dbi { font-size: 14px; display: block; }
  .dbchip b { display: block; font-size: 14px; margin-top: 1px; }
  .dbchip.bad b { color: var(--red); }
  .dbchip label { display: block; font-size: 9.5px; color: var(--muted); margin-top: 1px; letter-spacing: .2px; }
  .endStats.two { grid-template-columns: repeat(2, 1fr); }
  .endStats.one { grid-template-columns: 1fr; margin-bottom: 10px; }
  #stockBoard, #dailyBoard { margin: 16px 0 4px; padding: 14px 16px; border: 1px solid var(--grid); border-radius: 14px; background: var(--bg); text-align: left; }
  #stockBoard .dtitle, #dailyBoard .dtitle { font-size: 15px; font-weight: 800; color: var(--text); }
  #stockBoard .dsub, #dailyBoard .dsub { color: var(--muted); font-size: 12px; margin-top: 2px; }
  #stockBoard .lboard, #dailyBoard .lboard { margin-top: 10px; }
  .lrow .st { color: var(--gold); margin-left: 5px; font-size: 11px; }
  .lboard { margin-top: 12px; display: flex; flex-direction: column; gap: 2px; max-height: 44vh; overflow-y: auto; -webkit-overflow-scrolling: touch; }
  .lrow { display: grid; grid-template-columns: 28px 1fr auto; gap: 8px; padding: 6px 10px; border-radius: 8px; font-size: 13px; color: var(--muted); }
  .lrow span:nth-child(2) { color: var(--text); }
  .lrow.you { background: rgba(90,209,240,.12); border: 1px solid rgba(90,209,240,.4); }
  .lrow.you span { color: var(--line); font-weight: 800; }
  .lrow.promo span:first-child { color: var(--green); font-weight: 800; }
  .lrow.releg span:first-child { color: var(--red); font-weight: 800; }
  .lrow.gap { padding: 2px 10px; color: var(--muted); }
  .lrow.gap span:first-child { text-align: center; letter-spacing: 2px; }
  .lrow small.muted { color: var(--muted); font-weight: 400; font-size: 11px; margin-left: 4px; }
  .lrow.you small.muted { color: var(--line); }
  .lrow span.gold { color: var(--gold); font-weight: 800; }
  /* middle cell: fixed avatar + the NAME truncates (ellipsis) so a long handle never wraps the "best $X" /
     "Round N" sub-label onto a second line under the avatar (QA 2026-10-20: "ZeubiTradingWallah best" split). */
  .lrow .lmid { display: flex; align-items: center; gap: 5px; min-width: 0; }
  .lrow .lmid .lname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
  .lrow .lmid small.muted { white-space: nowrap; flex: 0 0 auto; margin-left: 0; }
  #tickerSearch { width: 100%; box-sizing: border-box; margin: 0 0 10px; padding: 10px 14px; border-radius: 10px;
    border: 1px solid var(--grid); background: var(--panel); color: var(--text); font-size: 15px; }
  #tickerSearch:focus { outline: none; border-color: var(--line); }

  /* rewarded-ad overlay (placeholder) */
  .modal { position: fixed; inset: 0; background: rgba(5,9,18,.94); display: flex; align-items: center; justify-content: center; z-index: 50; }
  #promoModal { z-index: 70; }   /* promotion popup sits above the end-game summary */
  #promoModal .adlabel { color: var(--gold); }
  /* 🎉 "New!" celebration on a tool unlock — a gold ribbon that pops, and the tool icon bounces in */
  .promonew { display: inline-block; margin: 0 auto 8px; background: var(--gold); color: #1a1230; font-weight: 900; font-size: 12px; letter-spacing: 1.5px; padding: 5px 14px; border-radius: 999px; animation: newpop .55s cubic-bezier(.2,1.5,.5,1) both; }
  @keyframes newpop { 0% { transform: scale(0) rotate(-10deg); opacity: 0; } 60% { transform: scale(1.22) rotate(3deg); } 100% { transform: scale(1) rotate(0); opacity: 1; } }
  .adcreative.newpop { animation: emojibounce .6s ease-out; }
  @keyframes emojibounce { 0% { transform: scale(.3); opacity: 0; } 50% { transform: scale(1.28); } 72% { transform: scale(.92); } 100% { transform: scale(1); opacity: 1; } }
  .modal.hidden { display: none; }
  /* Reload Stack slider + quick presets (greed-vs-safety stake picker) */
  .rlslider { -webkit-appearance: none; appearance: none; width: 86%; max-width: 320px; height: 8px; border-radius: 6px; margin: 14px auto 6px; display: block;
    background: linear-gradient(90deg, var(--gold), #e5556d); outline: none; cursor: pointer; }
  .rlslider::-webkit-slider-thumb { -webkit-appearance: none; width: 24px; height: 24px; border-radius: 50%; background: #fff; border: 3px solid var(--gold); cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,.4); }
  .rlslider::-moz-range-thumb { width: 22px; height: 22px; border-radius: 50%; background: #fff; border: 3px solid var(--gold); cursor: pointer; }
  /* launch-fix M2 (3.3): a gold tick + "Now $P" label under the stake slider, marking the carried position. The wrap
     owns the slider's width so the absolutely-positioned tick lines up with the track; the slider sits above the tick. */
  .rlslider-wrap { position: relative; width: 86%; max-width: 320px; margin: 14px auto 18px; }
  .rlslider-wrap .rlslider { position: relative; z-index: 1; width: 100%; margin: 0; }
  .rlnotch { position: absolute; top: 50%; height: 20px; width: 3px; background: var(--gold); transform: translate(-50%,-50%); border-radius: 2px; pointer-events: none; z-index: 0; box-shadow: 0 0 4px rgba(0,0,0,.6); }
  .rlnotch-lbl { position: absolute; top: 13px; left: 50%; transform: translateX(-50%); white-space: nowrap; font: 800 10px system-ui, sans-serif; color: var(--gold); letter-spacing: .2px; text-shadow: 0 1px 2px rgba(0,0,0,.6); }
  .rlpresets { display: flex; gap: 6px; justify-content: center; flex-wrap: wrap; margin-top: 8px; }
  .rlpresets button { background: rgba(160,107,255,.14); border: 1px solid rgba(160,107,255,.3); color: #e6dcff; border-radius: 9px; padding: 8px 12px; font-weight: 800; font-size: 13px; min-height: 40px; cursor: pointer; }
  .rlpresets button.on { background: var(--gold); color: #06220f; border-color: var(--gold); }
  /* risking banked money → unmistakable red warning on the slider thumb + confirm button */
  #reloadModal.risky #rlGo { background: var(--red) !important; color: #2a0a10 !important; }
  #reloadModal.risky .rlslider::-webkit-slider-thumb { border-color: var(--red); }
  #reloadModal.risky .rlslider::-moz-range-thumb { border-color: var(--red); }
  .adbox { width: min(420px, 86vw); background: var(--panel); border: 1px solid var(--grid); border-radius: 22px; padding: 26px; text-align: center; box-shadow: 0 18px 50px rgba(0,0,0,.45);
    --fl-pad: 26px;   /* N3: what a full-bleed child inside this sheet must offset by. See the max-height:679 override below. */ }
  /* launch-fix M2: the Liquidated/Reload modal is the tallest (KO Finn + slider + presets). Cap it to the viewport and
     let it scroll as a safety; on short screens (<640) tighten padding, drop the footer line, and the KO Finn shrinks
     to 96px (set in mountModal) so every child fits at 320x568 without scrolling. */
  #reloadModal .adbox { max-height: calc(100dvh - 16px); overflow: auto; }
  @media (max-height: 639px) { #reloadModal .adbox { padding: 16px; } #reloadModal #rlFoot { display: none; } }
  /* launch-fix Z: the one-time explainer card (#tipCard) */
  .tipcard { max-width: min(360px, 88vw); }
  .tipcard .tc-em { font-size: 40px; margin-bottom: 6px; line-height: 1; }
  .tipcard .tc-title { font-size: 19px; font-weight: 900; color: var(--line); letter-spacing: .2px; margin-bottom: 8px; text-wrap: balance; }
  .tipcard .tc-body { font-size: 14px; line-height: 1.45; color: var(--text); opacity: .92; }
  .tipcard .tc-body b { color: var(--gold); font-weight: 800; }
  .tipcard .tc-go { display: block; margin: 16px auto 0; background: var(--gold); color: #06220f; border: 0; border-radius: 10px; padding: 12px 24px; font-weight: 800; min-height: 46px; cursor: pointer; }
  @keyframes popin { from { opacity: 0; transform: translateY(10px) scale(.96); } to { opacity: 1; transform: none; } }
  .endbox, .adbox { animation: popin .2s ease both; }
  .adlabel { color: var(--muted); font: 700 11px ui-monospace, Menlo, monospace; letter-spacing: 2px; }
  .adcreative { font-size: 40px; margin: 16px 0 8px; }
  .adname { font-weight: 800; font-size: 18px; }
  .adtag { color: var(--muted); font-size: 13px; margin-top: 4px; }
  .adbar { height: 6px; background: var(--grid); border-radius: 99px; margin: 20px 0 10px; overflow: hidden; }
  #adFill { height: 100%; width: 0; background: linear-gradient(90deg, var(--line), var(--green)); }
  .adskip { color: var(--muted); font-size: 12px; }
  #nameInput { width: 260px; max-width: 76vw; margin: 18px auto 0; display: block; padding: 12px 14px; border-radius: 10px;
    border: 1px solid var(--grid); background: var(--bg); color: var(--text); font-size: 16px; text-align: center; }
  #nameInput:focus { outline: none; border-color: var(--line); }
  #nameModal button#nameBtn { display: block; margin: 16px auto 0; background: var(--line); color: #06222e; border: 0;
    border-radius: 10px; padding: 12px 26px; font-weight: 800; min-height: 46px; }

  /* challenge banner on game screen */
  .campchal { margin-top: 11px; font-size: 13px; color: var(--text); background: rgba(252,191,73,.10); border: 1px solid rgba(252,191,73,.4); border-radius: 10px; padding: 8px 11px; }
  .camptools { margin-top: 11px; font-size: 12.5px; color: var(--muted); display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
  .camptools .ptool { background: var(--panel); border: 1px solid var(--grid); border-radius: 8px; padding: 4px 9px; color: var(--text); font-weight: 600; }

  /* end card extras */
  .endStats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin: 18px 0 4px; }
  .endStats > div { background: var(--grid); border-radius: 12px; padding: 12px 8px; }
  .endStats label { display: block; color: var(--muted); font-size: 10.5px; text-transform: uppercase; letter-spacing: .5px; }
  .endStats .v { font-size: 23px; font-weight: 800; margin-top: 5px; font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; font-variant-numeric: tabular-nums; line-height: 1.1; white-space: nowrap; }   /* proportional + tabular digits → no monospace wide-comma "$1, 408" */
  .endStats .s2 { font-size: 12px; color: var(--muted); margin-top: 3px; }
  .endStats .star { color: var(--gold); } .endStats .star .dim { color: #3a4a66; }
  #perfectTile:hover { outline: 1px solid var(--line); }
  #perfectTile.on { outline: 1px solid var(--line); background: #1b2740; }
  #archetype { margin: 16px auto 2px; background: var(--grid); border-radius: 999px; padding: 8px 18px; width: fit-content; font-weight: 700; }
  #archetype .em { font-size: 20px; margin-right: 6px; }
  #archetype .ad { color: var(--muted); font-weight: 400; font-size: 13px; display: block; margin-top: 2px; }
  #chalResult { font-weight: 800; margin-top: 8px; }
  #tradeTape { font-size: 21px; letter-spacing: 3px; margin: 8px 0 2px; }
  #brag { font-size: 17px; font-weight: 800; margin: 14px 0 2px; }
  #brag .pct { color: var(--gold); } #brag .mkt { color: var(--green); } #brag .mktn { color: var(--red); }
  .levels { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 14px; }
  .card .lvlnum { font-size: 11px; font-weight: 700; color: var(--muted); margin-left: 7px; vertical-align: middle; }
  .card { position: relative; background: var(--panel); border: 1px solid var(--grid); border-radius: 16px;
    padding: 16px; text-align: left; color: var(--text); transition: transform .12s, border-color .12s; overflow: hidden; }
  .card.play { cursor: pointer; }
  .card.play:hover { transform: translateY(-3px); border-color: var(--line); }
  .card.locked { opacity: .5; }
  .card .lvl { color: var(--muted); font-size: 11px; letter-spacing: .8px; text-transform: uppercase; }
  .card .head { display: flex; align-items: center; gap: 10px; margin: 4px 0 2px; padding-right: 26px; }
  .card .emoji { font-size: 30px; }
  .tpill { display: inline-flex; align-items: center; border: 1px solid; border-radius: 8px; padding: 3px 10px; font-weight: 800; letter-spacing: .3px; vertical-align: middle; font-variant-numeric: tabular-nums; }
  .card .tic { font-size: 19px; font-weight: 800; }
  .card .nick { font-size: 13px; color: var(--muted); }
  .card .tag { font-size: 12.5px; color: var(--muted); margin: 10px 0 12px; min-height: 32px; line-height: 1.35; }
  .card .meta { display: flex; justify-content: space-between; font-size: 12px; color: var(--muted); border-top: 1px solid var(--grid); padding-top: 10px; }
  .card .diff { font-weight: 700; }
  .card .diff .dots { letter-spacing: 1px; margin-left: 5px; font-size: 11px; }
  .card .rec { margin-top: 8px; font-size: 13px; }
  .card .srow { display: flex; align-items: baseline; gap: 7px; font-size: 13px; margin-top: 7px; }
  .card .srow .sl { color: var(--muted); min-width: 28px; }
  .card .srow .sub { font-size: 12px; }
  .card .srow .rk { margin-left: auto; color: var(--line); font-weight: 700; font-size: 12px; }
  .card .srow .rk.gold { color: var(--gold); }
  .card .badge { position: absolute; top: 12px; right: 14px; font-size: 18px; }
  .flames { letter-spacing: 1px; }

  /* ---------- GAME ---------- */
  .topbar { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px; padding-right: 60px; }
  .backbtn { background: transparent; color: var(--muted); border: 1px solid var(--grid); border-radius: 10px; padding: 8px 14px; min-height: 40px; }
  .sub { color: var(--muted); font-size: 13px; }
  /* in-game subtitle: never wrap — the live win-count/% must not reflow the chart (layout-shift jerk) */
  #gameSub { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  #gameSub .wshort { display: none; }
  .hud { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin: 16px 0; }
  .stat { background: var(--panel); border: 1px solid var(--grid); border-radius: 14px; padding: 12px 14px; }
  .stat .label { color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: .6px; }
  #bhLabel .lblShort { display: none; }
  .stat .value { font-size: 21px; font-weight: 800; margin-top: 4px; font-variant-numeric: tabular-nums; }
  .light-row { display: flex; align-items: center; gap: 14px; margin: 2px 0 14px; }
  .light { width: 26px; height: 26px; border-radius: 50%; background: var(--green);
    box-shadow: 0 0 0 4px rgba(58,216,132,.18), 0 0 18px rgba(58,216,132,.6); transition: .25s; }
  .light.in { background: var(--red); box-shadow: 0 0 0 4px rgba(255,107,129,.18), 0 0 18px rgba(255,107,129,.7); }
  .light-row .txt { color: var(--muted); font-size: 14px; }
  .light-row .txt b { color: var(--text); }
  canvas { width: 100%; height: auto; background: var(--panel); border: 1px solid var(--grid); border-radius: 16px; display: block;
    cursor: pointer; touch-action: manipulation; -webkit-user-select: none; user-select: none; -webkit-tap-highlight-color: transparent; }
  /* BUG-19: a live Rush round's chart isn't a pressable surface (you trade with the ▲/▼ buttons; tokens auto-collect) — no pointer cursor, so a floating orb never looks tappable. */
  body.rush.rushlive #chart { cursor: default; }
  .hint { text-align: center; color: var(--muted); margin-top: 14px; font-size: 14px; }
  /* first-run coach: big self-teaching prompt on the chart, taps pass through to the game */
  .coach { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 8; pointer-events: none;
    text-align: center; font-weight: 900; font-size: 26px; color: var(--text); line-height: 1.35;
    text-shadow: 0 2px 14px rgba(0,0,0,.7); animation: coachpulse 1.1s ease-in-out infinite; padding: 0 24px; }
  .coach .sub { display: block; font-size: 14px; font-weight: 700; color: var(--line); margin-top: 6px; }
  @keyframes coachpulse { 0%,100% { transform: translate(-50%,-50%) scale(1); } 50% { transform: translate(-50%,-50%) scale(1.07); } }
  /* QA#11: the first-run hint — SMALLER, pinned to the very bottom edge (off the price action, not floating over the
     middle of the chart), and DISMISSABLE (tap it to clear; see the #coachRun tap handler in game.js). A tiny ✕ hint
     and pointer-events:auto make it tappable without eating chart taps elsewhere. */
  #chartWrap > .coach {
    top: auto; right: auto; bottom: 6px; left: 50%; transform: translateX(-50%);
    font-size: 14px; font-weight: 800; line-height: 1.25; max-width: 78%; white-space: normal;
    padding: 7px 30px 8px 14px; border-radius: 12px; color: var(--text); text-shadow: none; pointer-events: auto; cursor: pointer;
    background: rgba(11,17,32,.9); border: 1px solid rgba(255,255,255,.12);
    box-shadow: 0 6px 18px rgba(0,0,0,.5); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
    animation: startcue 1.5s ease-in-out infinite; }
  #chartWrap > .coach::after { content: "✕"; position: absolute; top: 4px; right: 8px; font-size: 12px; font-weight: 700; color: var(--muted); opacity: .75; }
  #chartWrap > .coach .sub { font-size: 11.5px; font-weight: 600; margin-top: 3px; opacity: .88; }
  /* launch-fix Z2/Z3 (F9) + ux-review (E): on a phone the centred coach strip covered the chart + the ▲ IN · LONG badge
     (confirmed at 320 AND 393 — the pill is the very thing the tooltip talks about). Pin it as a one-line strip just above
     the trade buttons (fixed, outside the chart), drop the sub-line (nothing to clip), LIFT #posBadge above the strip, and
     hide the decorative corner Finn while the coach is up. Z3 shipped this at <=340; ux-review E widens it to <=420 so 393
     gets the same clearance. */
  @media (max-width: 420px) {
    #chartWrap > .coach { position: fixed; left: 8px; right: 8px; bottom: 74px; top: auto; transform: none; max-width: none;
      overflow: visible; z-index: 9; padding: 6px 26px 6px 12px; font-size: 13px; line-height: 1.25; animation: none; }
    #chartWrap > .coach .sub { display: none; }
    #chartWrap:has(> .coach:not(.hidden)) #posBadge { bottom: 52px; }
    /* the chart's bottom-left has no free slot while the coach is up: the corner Finn owns bottom ~48-120px and the strip
       owns 0-56px, so the lifted badge would land ON the Finn. The Finn is decorative, the badge is live state — hide it. */
    #chartWrap:has(> .coach:not(.hidden)) #finnCorner { display: none; }
  }
  @keyframes startcue { 0%,100% { transform: translateX(-50%) scale(1); } 50% { transform: translateX(-50%) scale(1.03); } }
  /* Take-profit % picker — a paused overlay on the chart while you set the level */
  .sltp { position: absolute; inset: 0; z-index: 12; display: flex; align-items: center; justify-content: center;
    background: rgba(6,10,20,.55); -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px); }
  .sltp.hidden { display: none; }
  .sltpCard { background: var(--bg); border: 1px solid rgba(255,255,255,.12); border-radius: 16px; padding: 18px 18px 16px;
    box-shadow: 0 14px 44px rgba(0,0,0,.6); text-align: center; max-width: 330px; width: 86%; }
  .sltpTitle { font-size: 18px; font-weight: 800; color: var(--text); }
  .sltpSub { font-size: 12.5px; color: var(--muted); margin: 5px 0 15px; line-height: 1.4; }
  .sltpChips { display: flex; gap: 8px; justify-content: center; }
  .sltpChips button { flex: 1; padding: 13px 0; border-radius: 12px; border: 1px solid rgba(255,255,255,.14);
    background: var(--panel); color: var(--text); font-weight: 800; font-size: 17px; cursor: pointer; transition: transform .06s; }
  .sltpChips button:active { transform: scale(.94); }
  .sltpCard.sl .sltpChips button { border-color: rgba(255,107,129,.55); }
  .sltpCard.tp .sltpChips button { border-color: rgba(58,216,132,.55); }
  .sltpCancel { margin-top: 12px; background: none; border: none; color: var(--muted); font-size: 13px; font-weight: 700; cursor: pointer; padding: 6px 10px; }
  /* comeback banner: someone beat your challenge → tap to rematch */
  .comeback { display: block; width: 100%; text-align: left; margin: 0 0 14px; padding: 13px 16px; border-radius: 14px; cursor: pointer;
    border: 1px solid var(--red); background: linear-gradient(90deg, rgba(255,107,129,.18), rgba(255,209,102,.10));
    color: var(--text); font: inherit; font-weight: 800; font-size: 14px; line-height: 1.35; }
  .comeback .cbcta { float: right; color: var(--gold); font-weight: 900; margin-left: 10px; }
  .comeback:active { transform: scale(.99); }
  /* live commentary overlay on the chart */
  .livequip { position: absolute; top: 10px; left: 50%; transform: translateX(-50%) translateY(-6px);
    max-width: 88%; padding: 7px 14px; border-radius: 999px; background: rgba(20,29,51,.82);
    border: 1px solid var(--grid); color: var(--text); font-weight: 800; font-size: 14px; text-align: center; line-height: 1.25;
    pointer-events: none; opacity: 0; transition: opacity .18s ease, transform .18s ease; z-index: 6;
    -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); text-shadow: 0 1px 2px rgba(0,0,0,.5); }
  .livequip.show { opacity: 1; transform: translateX(-50%) translateY(0); }
  .livequip.big { font-size: 18px; padding: 9px 18px; color: var(--gold); border-color: var(--gold); animation: quippop .35s ease; }
  @keyframes quippop { 0% { transform: translateX(-50%) scale(.75); } 60% { transform: translateX(-50%) scale(1.08); } 100% { transform: translateX(-50%) scale(1); } }
  /* Market Intel news card — pauses the run, tap to continue */
  /* The held-tape panel sits ON the chart, not under it. As a block below, it took 35% of the
     chart's height every time it opened (541px -> 349px on a phone) — the play area shrank
     exactly when the player wanted to study it. Anchored top so the price action and any
     indicator strip along the bottom stay visible underneath. */
  /* Whether you are exposed is the single most important thing on screen and it was a line of
     grey text under the chart. It lives ON the chart now, colour-coded, and the frame itself
     lights up while a position is open. */
  /* E8: the position pill used to sit top-left, where it covered the chart's top-left price/TA labels (and the
     top price-axis label at ~410px). The top band of the plot is the label safe-zone; the pill now lives at the
     BOTTOM-left, clear of every top-anchored label (price axis, TA/MA callouts, SHORT MODE, the cursor tag). A
     max-width + ellipsis keep even a 6-char % ("+53.4%", "−100.0%") from ever stretching under the right-edge axis $labels. */
  .posbadge { position: absolute; left: 10px; bottom: 12px; top: auto; z-index: 5; pointer-events: none;
    max-width: calc(100% - 20px); overflow: hidden; text-overflow: ellipsis;
    padding: 5px 11px; border-radius: 999px; white-space: nowrap;
    font: 800 12.5px -apple-system, system-ui, sans-serif; letter-spacing: .2px;
    border: 1px solid transparent; }
  .posbadge.out  { background: rgba(9,15,28,.82); color: #93a4c2; border-color: rgba(147,164,194,.35); }
  .posbadge.win  { background: rgba(20,72,48,.92); color: #7bf0b2; border-color: rgba(123,240,178,.55); }
  .posbadge.lose { background: rgba(84,22,32,.92); color: #ff9aa8; border-color: rgba(255,154,168,.55); }
  #chartWrap.inpos { box-shadow: inset 0 0 0 2px rgba(123,240,178,.45); border-radius: 14px; }
  #chartWrap.inpos.losing { box-shadow: inset 0 0 0 2px rgba(255,154,168,.45); }
  @media (max-width: 640px) {
    .posbadge { font-size: 14.5px; padding: 7px 13px; left: 8px; bottom: 10px; top: auto; }
    /* QA#6: the desk toast ("🔄 Fresh chart…", "🏅 ROUND 5…") used to sit at top:10px and overlap the OUT·in-cash pill
       top-left. Drop it into its own slot clear of the badge, and cap its width so it never slides back under it. */
    .livequip { top: 48px; max-width: 76%; }
    .livequip.big { top: 46px; }
  }
  .rvpanel { position: absolute; left: 8px; right: 8px; top: 8px; display: none; z-index: 7;
    padding: 11px 13px; border-radius: 13px; background: rgba(9,15,28,.94);
    border: 1px solid var(--line); box-shadow: 0 10px 30px rgba(0,0,0,.45); }
  .rvpanel.show { display: block; }
  .rvpanel { max-height: 52%; overflow-y: auto; }   /* never swallow the figure it describes */
  /* the card sits opposite the target: a figure aiming UP gets the card at the bottom, so the
     measured-move line it just drew is never hidden behind the text describing it */
  .rvpanel.low { top: auto; bottom: 8px; }
  .rvpanel .rvhead { color: var(--acc, #5ee09c); font: 800 10px ui-monospace, Menlo, monospace; letter-spacing: 1.5px; }
  .rvpanel .rvtitle { color: var(--text); font-size: 15px; font-weight: 800; margin: 4px 0 4px; line-height: 1.2; }
  .rvpanel .rvwhy { color: var(--muted); font-size: 12px; line-height: 1.4; }
  .rvpanel .rvwhy b { color: var(--text); }
  /* Level 1 coaching strip. Overlays the TOP of the plot rather than sitting above it in flow:
     an element that joins and leaves the layout resizes the canvas mid-run, which is what made the
     chart stretch when the old pop-up opened. */
  .tutbar { position:absolute; left:8px; right:8px; top:8px; z-index:6; pointer-events:none;
    background: rgba(10,16,32,.94); border:1px solid var(--line); border-radius:12px;
    padding:9px 12px; text-align:left; opacity:0; transform:translateY(-6px);
    transition:opacity .18s ease, transform .18s ease; }
  .tutbar.show { opacity:1; transform:none; }
  .tutbar { text-align:center; }
  .tutbar .tbtip { font-size:15px; font-weight:800; letter-spacing:.2px; color: var(--text); }
  .tutbar .tbtip.buy { color:#6de0a0; } .tutbar .tbtip.sell { color: var(--gold); }
  @media (max-width: 640px) { .tutbar .tbtip { font-size:17px; } }
  .rvpanel .rvcue { margin-top: 10px; padding: 9px 12px; border-radius: 10px; text-align: center;
    background: var(--line); color: #06222e; font-weight: 800; font-size: 13.5px; }
  @media (max-width: 640px) { .rvpanel .rvcue { font-size: 15px; padding: 12px; } }
  .rvpanel .rvbtns { display: flex; gap: 8px; margin-top: 10px; }
  .rvpanel .rvact { flex: 1 1 0; min-height: 40px; border-radius: 10px; cursor: pointer;
    border: 1px solid var(--grid); background: var(--elev, #16203a); color: var(--text); font-weight: 800; font-size: 13px; }
  .rvpanel .rvact.buy { background: #5ee09c; color: #06210f; border-color: #5ee09c; }
  .rvpanel .rvact.go { background: var(--line); color: #0b1220; border-color: var(--line); }
  @media (max-width: 640px) {
    .rvpanel { padding: 13px 14px; }
    .rvpanel .rvtitle { font-size: 17px; }
    .rvpanel .rvwhy { font-size: 13.5px; }
    .rvpanel .rvact { min-height: 46px; font-size: 15px; }
  }
  .revealtip { position: absolute; left: 50%; top: 10px; transform: translateX(-50%); display: none;
    align-items: center; gap: 10px; padding: 6px 8px 6px 14px; border-radius: 999px; white-space: nowrap;
    background: rgba(9,15,28,.92); border: 1px solid var(--grid); z-index: 6;
    pointer-events: none; }                      /* the chart keeps taking taps; only the button doesn't */
  .revealtip.show { display: flex; }
  .revealtip .rvmsg { color: #ffd166; font-weight: 800; font-size: 13px; letter-spacing: .2px; }
  .revealtip .rvbtn { pointer-events: auto; min-height: 34px; padding: 0 13px; border-radius: 999px;
    border: 1px solid var(--line); background: var(--line); color: #0b1220; cursor: pointer;
    font-weight: 800; font-size: 12.5px; display: inline-flex; align-items: center; gap: 5px; }
  .revealtip .rvbtn:active { transform: translateY(1px); }
  @media (max-width: 640px) {
    .revealtip { top: 8px; gap: 8px; padding: 6px 7px 6px 12px; }
    .revealtip .rvmsg { font-size: 14px; }
    .revealtip .rvbtn { min-height: 44px; font-size: 13.5px; padding: 0 13px; }
  }
  .patcard { display: none; margin: 8px 0 0; padding: 12px 14px; background: var(--panel);
    border: 1px solid var(--line); border-radius: 14px; text-align: left; box-shadow: 0 10px 30px rgba(0,0,0,.35); }
  .patcard.show { display: block; }
  .patcard .pchead { color: var(--line); font: 800 10.5px ui-monospace, Menlo, monospace; letter-spacing: 1.6px; }
  .patcard .pctitle { color: var(--text); font-size: 16px; font-weight: 800; margin: 5px 0 6px; line-height: 1.25; }
  .patcard .pcwhy { color: var(--muted); font-size: 12.5px; line-height: 1.45; }
  .patcard .pcwhy b, .patcard .pchint b { color: var(--text); }
  .patcard .pchint { color: var(--muted); font-size: 12px; line-height: 1.4; margin-top: 7px;
    border-left: 2px solid var(--grid); padding-left: 9px; }
  .patcard .pcbtns { display: flex; gap: 8px; margin-top: 11px; }
  .patcard .pcbtn { flex: 1 1 auto; min-height: 42px; border-radius: 10px; border: 1px solid var(--grid);
    background: var(--bg); color: var(--text); font-weight: 800; font-size: 13.5px; cursor: pointer; padding: 0 12px; }
  .patcard .pcbtn.go { background: var(--line); color: #0b1220; border-color: var(--line); }
  .patcard .pchead.ok { color: var(--green); }
  .patcard .pchead.no { color: var(--muted); }
  .patcard .pcbtn.buy { background: var(--green); color: #06281a; border-color: var(--green); }
  .patcard .pcbtn.sell { background: #a78bfa; color: #1a0f33; border-color: #a78bfa; }
  .patcard .pctools { margin-top: 10px; display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px; }
  .patcard .ptlabel { grid-column: 1 / -1; font-size: 10.5px; color: var(--muted); font-weight: 700; letter-spacing: .3px; }
  .patcard .itool { text-align: left; border: 1px solid var(--grid); background: var(--bg); color: var(--text);
    border-radius: 10px; padding: 7px 9px; font-weight: 800; font-size: 12.5px; cursor: pointer; line-height: 1.15; }
  .patcard .itool span { display: block; font-weight: 600; font-size: 10px; color: var(--muted); margin-top: 2px; }
  .patcard .itool.on { border-color: var(--line); background: rgba(90,209,240,.12); }
  .patcard .itool.off { opacity: .38; cursor: not-allowed; }
  .intelcard { position: absolute; top: 46px; left: 50%; transform: translateX(-50%) scale(.85); width: min(82%, 360px);
    background: linear-gradient(135deg, #1d2b48, #141d33); border: 1px solid var(--gold); border-radius: 16px; padding: 16px 20px;
    text-align: center; pointer-events: none; opacity: 0; transition: opacity .2s ease, transform .2s ease; z-index: 8;
    box-shadow: 0 12px 40px rgba(0,0,0,.5); }   /* #7: anchored to the UPPER chart, not dead-centre, so the live price line + its $tag (which tracks the cursor mid-chart) stay readable behind the news */
  .intelcard.show { opacity: 1; transform: translateX(-50%) scale(1); pointer-events: auto; cursor: pointer; }
  .intelcard .ithead { color: var(--gold); font: 800 11px ui-monospace, Menlo, monospace; letter-spacing: 2px; text-transform: uppercase; }
  .intelcard .itconf { font: 800 12.5px ui-monospace, Menlo, monospace; letter-spacing: 1.5px; margin-top: 7px; }   /* #2: how much to trust this call */
  .intelcard .itbody { color: var(--text); font-size: 16px; font-weight: 700; line-height: 1.35; margin: 10px 0 12px; }
  .intelcard .itfoot { color: var(--muted); font-size: 12px; font-weight: 600; }
  #intelBtn.on, #slowBtn.on { background: var(--gold); color: #1a1505; }
  .powerups { display: flex; gap: 8px; justify-content: center; margin-top: 12px; flex-wrap: wrap; }
  .powerups:empty { display: none; }
  /* ---- your-call trade buttons (both-ways levels only) ---- */
  .tradebtns { display: flex; gap: 10px; margin-top: 8px; }
  .tradebtns.hidden { display: none; }
  .tradebtn { flex: 1; min-height: 54px; border: 0; border-radius: 12px; font-size: 17px; font-weight: 900; letter-spacing: .3px;
    cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    transition: filter .12s, transform .06s, opacity .15s, box-shadow .15s; -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
  .tradebtn.buy   { background: var(--green); color: #04210f; box-shadow: 0 6px 18px rgba(58,216,132,.30); }
  .tradebtn.short { background: var(--red);   color: #2a0710; box-shadow: 0 6px 18px rgba(255,107,129,.30); }
  .tradebtn.dim   { opacity: .5; box-shadow: none; }
  /* E9: an overlay is open (Market Intel, Liquidated/Reload, round summary, pause…) → BUY/SELL read clearly inert:
     dimmed, no glow, and no pointer events, so a tap can't sneak a trade through behind the card. Restored on close. */
  .tradebtn.ovdim { opacity: .32; box-shadow: none; filter: grayscale(.5); pointer-events: none; }
  /* fix K: the 400 ms post-close OPEN lock — the buttons dim so the brief "can't re-open yet" window is visible. */
  .tradebtn.locked { opacity: .6; }
  .tradebtn.armed { outline: 3px solid var(--gold); outline-offset: 2px; box-shadow: 0 0 18px rgba(255,209,102,.65); animation: closePulse 0.9s ease-in-out infinite; }   /* BUG-04: pre-armed during the 3-2-1 → unmistakable it will fire at GO */
  .tradebtn.closing { color: #fff; animation: closePulse 1.1s ease-in-out infinite; }
  .tradebtn.buy.closing   { background: #2fbf73; }
  .tradebtn.short.closing { background: #e5556d; }
  .tradebtn[disabled] { opacity: .26; filter: grayscale(.4); cursor: default; box-shadow: none; }
  .tradebtn:active { transform: translateY(1px); }
  @keyframes closePulse { 0%,100% { box-shadow: 0 0 0 2px rgba(255,255,255,.55), 0 6px 20px rgba(0,0,0,.30); } 50% { box-shadow: 0 0 0 3px rgba(255,255,255,.95), 0 6px 24px rgba(0,0,0,.40); } }
  /* first time a tool is offered: a single ~1.2s big→small→big pulse, then it settles to normal */
  .pu.fresh { animation: puPulse 1.2s ease-in-out 1 both; }
  @keyframes puPulse {
    0%   { transform: scale(1);    box-shadow: 0 0 0 2px var(--gold), 0 0 16px rgba(252,191,73,.55); }
    22%  { transform: scale(1.16); }
    55%  { transform: scale(.93);  }
    80%  { transform: scale(1.1);  }
    100% { transform: scale(1);    box-shadow: 0 0 0 0 rgba(252,191,73,0); }
  }
  #puNew { display: none; text-align: center; font-size: 12px; font-weight: 800; color: var(--gold); margin-top: 7px; }
  .pu.spent { opacity: .45; }   /* a used live tool (Peek) — grayed out for the rest of the run */
  .powerups .pu { flex: 1; max-width: 220px; justify-content: center; border-radius: 10px; padding: 9px 14px; font-size: 13.5px; font-weight: 700; min-height: 42px; border: 0; display: inline-flex; align-items: center; gap: 6px; background: var(--panel); border: 1px solid var(--grid); color: var(--text); transition: background .15s, border-color .15s, color .15s; }
  .powerups .pu.on { background: rgba(90,209,240,.18); border-color: var(--line); color: var(--line); box-shadow: inset 0 0 0 1px var(--line); }   /* selected/active tool — distinct colour */
  .powerups .pu.using { animation: puUse .5s ease-out 1; }   /* flash the button the moment a tool fires */
  @keyframes puUse { 0% { transform: scale(1); } 30% { transform: scale(1.16); box-shadow: 0 0 16px var(--line), inset 0 0 0 1px var(--line); } 100% { transform: scale(1); } }
  @keyframes coinSpend { 0% { opacity: 0; transform: translateY(0) scale(.8); } 20% { opacity: 1; transform: translateY(-4px) scale(1.05); } 100% { opacity: 0; transform: translateY(-24px) scale(1); } }
  .coinspend { position: fixed; z-index: 60; font-weight: 900; font-size: 15px; color: var(--red); pointer-events: none; animation: coinSpend .9s ease-out both; display: inline-flex; align-items: center; gap: 3px; }
  @keyframes coinBump { 0%,100% { transform: scale(1); } 40% { transform: scale(1.28); color: var(--red); } }
  #coinsVal.spend { animation: coinBump .45s ease-out 1; }
  .btn-primary { background: var(--line); color: #06222e; }
  .btn-ghost { background: transparent; color: var(--muted); border: 1px solid var(--grid) !important; }
  .btn-go { background: var(--green); color: #04210f; font-size: 15px !important; padding-left: 22px !important; padding-right: 22px !important;
    box-shadow: 0 0 0 1px rgba(58,216,132,.5), 0 8px 24px rgba(58,216,132,.35); animation: gopulse 1.6s ease-in-out infinite; }
  @keyframes gopulse { 0%,100% { box-shadow: 0 0 0 1px rgba(58,216,132,.5), 0 8px 24px rgba(58,216,132,.3); } 50% { box-shadow: 0 0 0 1px rgba(58,216,132,.7), 0 8px 30px rgba(58,216,132,.55); } }

  /* ---- phones: chart-first game screen ---- */
  @media (max-width: 640px) {
    .wrap { padding: 12px 8px 28px; }
    #gameScreen .topbar { margin-bottom: 6px; position: relative; }
    /* bottom-right of the topbar, not top-right: at 375px the chip sat on top of the level title,
       and the top-right corner is the ☰ menu's now. */
    .gcoins { position: absolute; bottom: 0; right: 56px; display: inline-flex; align-items: center; gap: 4px; font-weight: 900; font-size: 15px; color: var(--gold); background: rgba(255,209,102,.12); border: 1px solid rgba(255,209,102,.32); border-radius: 20px; padding: 4px 11px; }
    .gcoins.spend { animation: coinBump .45s ease-out 1; }
    #gameTitle small { display: block; font-size: 12px; font-weight: 600; color: var(--muted); margin-top: 1px; }
    .topbar h1 { font-size: 18px; }
    .backbtn { padding: 7px 11px; min-height: 36px; font-size: 13px; }
    .sub { font-size: 11.5px; }
    #gameSub .wfull { display: none; }            /* "winning trades" -> "wins" so the line fits on one row */
    #gameSub .wshort { display: inline; }
    /* keep only the three numbers that matter; the rest is on the chart */
    .hud { grid-template-columns: repeat(3, 1fr); gap: 6px; margin: 8px 0; }
    .hud .stat:nth-child(2), .hud .stat:nth-child(3), .hud .stat:nth-child(6) { display: none; }
    .stat { padding: 7px 9px; }
    .stat .label { font-size: 9.5px; letter-spacing: .3px; white-space: nowrap; }
    .stat .value { font-size: 15px; margin-top: 2px; white-space: nowrap; }
    #bhLabel .lblFull { display: none; }
    #bhLabel .lblShort { display: inline; }
    .light-row { display: none; }          /* status is shown by the big green/red cursor */
    #chart { border-radius: 14px; margin-top: 2px; }
    .hint { font-size: 12px; margin: 10px 0 0; }
    /* in-game = locked single screen: stats up top, chart fills the middle, controls pinned at bottom, no scroll */
    body.playing { overflow: hidden; overscroll-behavior: none; }   /* block pull-to-refresh mid-run (only) so a swipe can't reload the game */
    body.playing #resourceBar { display: none; }
    body.playing #gameScreen { position: fixed; inset: 0; z-index: 35; background: var(--bg);
      display: flex; flex-direction: column; gap: 6px; overflow: hidden;
      padding: calc(8px + env(safe-area-inset-top)) 14px calc(10px + env(safe-area-inset-bottom)); }
    body.playing #gameScreen .topbar,
    body.playing #gameScreen .hud,
    body.playing #gameScreen .powerups { flex: 0 0 auto; margin: 0; }
    body.playing #gameScreen .hud { margin: 6px 0; }
    body.playing #gameScreen .powerups { margin: 6px 0 0; }
    body.playing #gameScreen .hint { display: none; }
    body.playing #gameScreen #tradeBtns { flex: 0 0 auto; margin: 6px 0 0; }
    body.playing #gameScreen #chartWrap { flex: 1 1 auto; min-height: 0; display: flex; }
    body.playing #gameScreen .patcard { flex: 0 0 auto; margin: 6px 0 0; max-height: 42vh; overflow-y: auto; }
    body.playing #gameScreen #chart { flex: 1 1 auto; min-height: 0; height: 100%; width: 100%; }
  }

  /* ===== BUG-18: DESKTOP (≥1024px). The game used to sit as a narrow in-flow column ~412px tall at the top
     of the 1040px .wrap, leaving ~60% of a 1440×900 screen empty and the chart small. Mobile is the
     reference, so adopt its locked full-viewport layout here too — but as a CENTERED wide column (uses the
     horizontal space) with the chart flexing to fill the height (≥55% at 1440×900), controls pinned top and
     bottom, no page scroll. Everything below <1024px is left exactly as it was. ===== */
  @media (min-width: 1024px) {
    body.playing { overflow: hidden; }
    body.playing #resourceBar { display: none; }
    body.playing #gameScreen { position: fixed; inset: 0; z-index: 35; background: var(--bg);
      display: flex; flex-direction: column; align-items: center; gap: 8px; overflow: hidden;
      padding: 18px 24px 20px; }
    /* cap + center each in-flow panel; the child combinator spares overlays/modals (position:fixed/absolute) */
    body.playing #gameScreen > .topbar,
    body.playing #gameScreen > .hud,
    body.playing #gameScreen > #rushBar,
    body.playing #gameScreen > #rushProg,
    body.playing #gameScreen > .light-row,
    body.playing #gameScreen > #tradeBtns,
    body.playing #gameScreen > .powerups,
    body.playing #gameScreen > #patternCard { flex: 0 0 auto; width: 100%; max-width: 1320px; margin: 0; }
    body.playing #gameScreen .hint { display: none; }
    body.playing #gameScreen > #chartWrap { flex: 1 1 auto; width: 100%; max-width: 1320px; min-height: 0; margin: 0; display: flex; }
    body.playing #gameScreen #chart { flex: 1 1 auto; min-height: 0; height: 100%; width: 100%; }
    body.playing #gameScreen .patcard { max-height: 42vh; overflow-y: auto; }
  }
  /* BUG-18: the keyboard-shortcut row in the How-to-play is desktop-only (shortcuts don't exist on touch) */
  @media (max-width: 1023px) { .kbdhelp { display: none; } }

  /* ---- design polish: terminal numbers, button feedback, juice ---- */
  .stat .value, .profile .rating, #ratingLine b, #portfolio, #price, #pnl, #vsbh {
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; font-variant-numeric: tabular-nums; }   /* tabular digits keep columns aligned WITHOUT the monospace wide-comma/period ("$976 . 38") */
  button { transition: filter .12s ease, transform .06s ease; }
  button:hover { filter: brightness(1.1); }
  button:active { transform: translateY(1px); }
  .card.play:active { transform: translateY(-1px) scale(.995); }
  #price.tickUp { color: var(--green) !important; } #price.tickDn { color: var(--red) !important; }

  .exitbtn { position: fixed; top: 14px; right: 14px; z-index: 46; width: 40px; height: 40px; border-radius: 10px;
    background: var(--panel); border: 1px solid var(--grid); color: var(--muted); display: flex; align-items: center; justify-content: center; font-size: 18px; line-height: 1; }
  .exitbtn:hover { color: var(--text); }
  .exitbtn.hidden { display: none; }
  .runmenu { position: fixed; top: 60px; right: 14px; z-index: 47; width: 210px; padding: 6px;
    background: var(--panel); border: 1px solid var(--grid); border-radius: 12px; box-shadow: 0 12px 34px rgba(0,0,0,.5); }
  .runmenu.hidden { display: none; }
  .rmitem { display: flex; align-items: center; gap: 9px; width: 100%; min-height: 44px; padding: 8px 10px;
    background: transparent; border: 0; border-radius: 9px; color: var(--text); font-weight: 700; font-size: 14px; text-align: left; }
  .rmitem span { display: flex; flex-direction: column; line-height: 1.2; }
  .rmitem small { font-size: 10.5px; font-weight: 600; color: var(--muted); }
  .rmitem:hover { background: var(--bg); }
  .rmitem.danger { color: var(--red); }
  .rmitem.danger small { color: var(--red); opacity: .8; }
  .rmitem.on { color: var(--line); } .rmitem.on small { color: var(--line); }
  /* the pre-run cue, on the chart where the tap lands */
  .startcue { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 8;
    display: flex; flex-direction: column; align-items: center; gap: 3px; pointer-events: none;
    padding: 12px 22px; border-radius: 14px; background: rgba(11,22,33,.78); border: 1px solid var(--grid);
    animation: cuePulse 2s ease-in-out infinite; }
  .startcue b { font-size: 17px; font-weight: 800; color: var(--line); letter-spacing: .3px; }
  .startcue span { font-size: 11.5px; color: var(--muted); }
  .startcue.hidden { display: none; }
  /* low and centred: clear of the price label, which follows the cursor through the middle of the
     plot, and clear of the menu panel it belongs to, which hangs from the top right */
  .startcue.paused { animation: none; top: auto; bottom: 7%; transform: translateX(-50%); padding: 8px 16px; }
  .startcue.paused b { color: var(--muted); font-size: 14px; }
  .startcue.paused span { font-size: 11px; }
  @keyframes cuePulse { 0%,100% { opacity: .96; } 50% { opacity: .62; } }
  .backToResults { position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%); z-index: 45;
    display: inline-flex; align-items: center; gap: 7px; background: var(--line); color: #06222e; border: 0;
    border-radius: 11px; padding: 12px 22px; font-weight: 800; min-height: 46px; box-shadow: 0 8px 26px rgba(0,0,0,.4); }

  /* confetti / celebration */
  #fx { position: fixed; inset: 0; pointer-events: none; z-index: 60; overflow: hidden; }
  .confetti { position: absolute; top: -14px; width: 8px; height: 14px; border-radius: 2px; animation: fall 1.7s linear forwards; }
  @keyframes fall { to { transform: translateY(106vh) rotate(560deg); opacity: .15; } }
  .coinfx { position: fixed; z-index: 61; pointer-events: none; will-change: transform, opacity;
    animation: coinpop var(--dur, .9s) cubic-bezier(.18,.7,.3,1) forwards; }
  .coinfx svg { display: block; filter: drop-shadow(0 2px 3px rgba(0,0,0,.35)); }
  @keyframes coinpop {
    0%   { transform: translate(-50%, -50%) scale(.3); opacity: 0; }
    18%  { opacity: 1; }
    100% { transform: translate(calc(-50% + var(--dx, 0px)), calc(-50% + var(--dy, -120px))) scale(1) rotate(var(--rot, 180deg)); opacity: 0; }
  }
  .rankup { position: fixed; left: 50%; top: 18%; transform: translateX(-50%); z-index: 61; pointer-events: none;
    background: var(--gold); color: #1a1300; font-weight: 900; letter-spacing: .5px; padding: 12px 22px; border-radius: 12px;
    box-shadow: 0 10px 40px rgba(252,191,73,.4); animation: rankpop 2.2s ease both; }
  @keyframes rankpop { 0% { opacity: 0; transform: translateX(-50%) scale(.7); } 12%,80% { opacity: 1; transform: translateX(-50%) scale(1); } 100% { opacity: 0; transform: translateX(-50%) scale(1) translateY(-12px); } }

  .endbox { text-align: center; background: var(--panel); border: 1px solid var(--grid); border-radius: 22px; padding: 24px; width: min(620px, 92vw); max-height: 92vh; overflow-y: auto; box-shadow: 0 18px 50px rgba(0,0,0,.45); }
  .endbox h2 { margin: 0 0 8px; font-size: 24px; }
  .endbox p { color: var(--muted); margin: 6px 0; }
  #recordBanner { display: none; margin: 0 auto 14px; background: rgba(252,191,73,.12); border: 1px solid var(--gold);
    color: var(--gold); font-weight: 800; padding: 8px 16px; border-radius: 999px; width: fit-content; letter-spacing: .5px; }
  #recordBanner.muted { background: rgba(139,155,180,.12); border-color: var(--grid); color: var(--muted); letter-spacing: .2px; }
  #quip { color: var(--text); font-size: 14px; font-weight: 600; margin: 2px 0 10px; opacity: .92; line-height: 1.35; }
  /* core-loop juice */
  #gameScreen { position: relative; }
  /* launch-fix C2: floats anchor by their TOP edge (translateX only, origin top-centre) so js stacks them by real top edges and nothing drifts up over the HUD / Cash Out. */
  .floatnum { position: absolute; transform: translateX(-50%); transform-origin: 50% 0; font-weight: 800; font-size: 26px; pointer-events: none; z-index: 25;
    padding: 2px 13px; border-radius: 13px; background: rgba(9,14,27,.74); box-shadow: 0 3px 12px rgba(0,0,0,.5); white-space: nowrap;
    text-shadow: 0 1px 3px rgba(0,0,0,.85); animation: floatupC2 .95s cubic-bezier(.2,.7,.3,1) forwards; }
  .floatnum.pos { color: var(--green); } .floatnum.neg { color: var(--red); } .floatnum.gold { color: var(--gold); }
  /* fix 6: a sentence-long float wraps + stays inside the viewport (so inside the chart) instead of clipping at 320-393px. */
  .floatnum.wrap { white-space: normal; max-width: min(92vw, 340px); font-size: clamp(16px, 4.6vw, 20px); line-height: 1.25; text-align: center; }
  /* launch-fix C2: bonus pills anchor by their TOP edge and shrink-wrap to their text (max-content, capped 360/92vw), so js stacks them by real height and they never balloon to half-screen or drift up over Cash Out / the header. */
  .floatnum.bonus { font-size: 18px; font-weight: 800; padding: 10px 18px; border-radius: 18px; white-space: normal; width: max-content; max-width: min(92vw, 360px); text-align: center; line-height: 1.28;
    transform: translateX(-50%); transform-origin: 50% 0;
    background: rgba(14,22,42,.95); border: 1px solid rgba(255,255,255,.2); box-shadow: 0 6px 22px rgba(0,0,0,.5);
    animation: bonuspopC2 1.85s cubic-bezier(.2,.7,.3,1) forwards; }
  .floatnum.bonus.gold { border-color: rgba(255,209,102,.65); } .floatnum.bonus.neg { border-color: rgba(255,120,140,.6); } .floatnum.bonus.pos { border-color: rgba(90,220,150,.6); }
  /* launch-fix Z3 (F5): compact one-line pill — the fallback when neither above nor below the price tag fits. Narrower
     (nowrap, smaller, tighter) so, centred, it clears the tag (which sits right-of-centre) horizontally. */
  .floatnum.bonus.compact { white-space: nowrap; width: max-content; max-width: min(66vw, 240px); font-size: 15px; padding: 7px 13px; line-height: 1.2; overflow: hidden; text-overflow: ellipsis; }
  /* launch-fix C2: plain floats — pop in (origin top, so the bottom edge barely moves), hold, fade; never drift up. */
  @keyframes floatupC2 { 0% { opacity: 0; transform: translateX(-50%) scale(.8); } 18% { opacity: 1; transform: translateX(-50%) scale(1.06); } 32% { transform: translateX(-50%) scale(1); } 72% { opacity: 1; transform: translateX(-50%) scale(1); } 100% { opacity: 0; transform: translateX(-50%) translateY(8px) scale(1); } }
  /* launch-fix C2: bonus pills — a gentle in-place pop (small scale so a tall pill can't poke past the stack gap), hold, settle out. */
  @keyframes bonuspopC2 { 0% { opacity: 0; transform: translateX(-50%) scale(.85); } 10% { opacity: 1; transform: translateX(-50%) scale(1.03); } 20% { transform: translateX(-50%) scale(1); } 85% { opacity: 1; transform: translateX(-50%) scale(1); } 100% { opacity: 0; transform: translateX(-50%) translateY(10px) scale(1); } }
  /* close-popups (Julien 2026-11-12): Rush reward pills + sentence floats sit on the chart's right side, away from the
     price — smaller, see-through, ~1.2s. Declared after .bonus/.wrap so these win at equal specificity. */
  .floatnum.side { transform: none; transform-origin: 100% 50%; font-size: 14px; font-weight: 800; padding: 6px 11px; border-radius: 13px;
    white-space: normal; width: max-content; text-align: right; line-height: 1.25; background: rgba(14,22,42,.6);
    border: 1px solid rgba(255,255,255,.14); box-shadow: 0 3px 10px rgba(0,0,0,.3); animation: sidepopCP 1.2s ease-out forwards; }
  .floatnum.side.gold { border-color: rgba(255,209,102,.4); } .floatnum.side.neg { border-color: rgba(255,120,140,.4); } .floatnum.side.pos { border-color: rgba(90,220,150,.4); }
  @keyframes sidepopCP { 0% { opacity: 0; transform: translateX(10px); } 14% { opacity: 1; transform: none; } 78% { opacity: 1; } 100% { opacity: 0; } }
  /* close-popups: the HUD combo cell pulses instead of a chart pill — transform only, so nothing reflows */
  .hudbump { animation: hudbumpCP .55s ease-out; }
  @keyframes hudbumpCP { 0% { transform: scale(1); } 35% { transform: scale(1.22); } 100% { transform: scale(1); } }
  @media (prefers-reduced-motion: reduce) { .floatnum.side { animation-duration: 1.2s; animation-name: sidefadeCP; } .hudbump { animation: none; } }
  @keyframes sidefadeCP { 0% { opacity: 0; } 10% { opacity: 1; } 80% { opacity: 1; } 100% { opacity: 0; } }
  .floatcoin { position: absolute; transform: translate(-50%,-50%); font-weight: 900; font-size: 22px; color: var(--gold); pointer-events: none; z-index: 26;
    display: inline-flex; align-items: center; gap: 4px; text-shadow: 0 2px 10px rgba(0,0,0,.55); animation: floatup .95s cubic-bezier(.2,.7,.3,1) forwards; }
  @keyframes floatup { 0% { opacity: 0; transform: translate(-50%,-30%) scale(.7); } 18% { opacity: 1; transform: translate(-50%,-50%) scale(1.12); } 100% { opacity: 0; transform: translate(-50%,-135%) scale(1); } }
  #chart.pulse { animation: pulseFx .45s ease-out; }
  @keyframes pulseFx { 0% { box-shadow: 0 0 0 0 rgba(58,216,132,0); } 30% { box-shadow: 0 0 0 3px rgba(58,216,132,.55), 0 0 34px rgba(58,216,132,.4); } 100% { box-shadow: 0 0 0 0 rgba(58,216,132,0); } }
  #chart.shake { animation: shakeFx .4s ease-in-out; }
  @keyframes shakeFx { 0%,100% { transform: translateX(0); } 20% { transform: translateX(-5px); } 40% { transform: translateX(5px); } 60% { transform: translateX(-3px); } 80% { transform: translateX(3px); } }
  /* qa-polish (8c): the win accent on a close >= WIN_CELEB_PCT — the light mirror of the liquidation's red shake.
     z-index 5 is DELIBERATE and is how "never over the corner Finn or the chips" is enforced: the glow paints
     under #finnCorner (z 6), .rushfx (z 24) and .floatnum (z 25), so it can never obscure any of them. inset:0 on
     an already position:relative #chartWrap and pointer-events:none mean it costs no layout and eats no tap.
     A soft bloom and NO crisp inner ring: #chartWrap.inpos (above) is a 2px green inset ring meaning "you are in
     a position", and the close that triggers this accent has just removed it — a ring here read as "still in",
     for 460ms, right at the moment the player left. The bloom alone reads as a flash, which is what it is. */
  #winGlow { position: absolute; inset: 0; z-index: 5; pointer-events: none; border-radius: 14px; opacity: 0;
    box-shadow: inset 0 0 40px 10px rgba(123,240,178,.40); }
  #winGlow.on { animation: winGlowFx .46s ease-out forwards; }
  @keyframes winGlowFx { 0% { opacity: 0; } 22% { opacity: 1; } 100% { opacity: 0; } }
  /* the gold burst off the P&L float. Lives in #fx (fixed, inset 0, pointer-events:none), so a spark is placed in
     viewport coords and never touches layout. --dx/--dy carry its outward travel; transform+opacity only. */
  .winspark { position: absolute; width: 7px; height: 7px; border-radius: 50%; pointer-events: none; will-change: transform, opacity;
    background: radial-gradient(circle, #fff6cf 0%, #ffd166 55%, rgba(255,209,102,0) 100%);
    animation: winSparkFx .46s cubic-bezier(.2,.7,.3,1) forwards; }
  @keyframes winSparkFx { 0% { opacity: 0; transform: translate(0,0) scale(.5); } 18% { opacity: 1; } 100% { opacity: 0; transform: translate(var(--dx,0px), var(--dy,0px)) scale(1.15); } }
  /* reduced motion: the glow only (it animates opacity, nothing moves). The travelling sparks are dropped. */
  @media (prefers-reduced-motion: reduce) { .winspark { display: none; } }
  #earnedCoins { display: none; font-size: 18px; font-weight: 800; margin: 4px 0 12px; }
  #earnedCoins b { font-size: 24px; }
  .lnk { background: none; border: 0; color: var(--muted); font-size: 13px; cursor: pointer; margin-top: 16px; text-decoration: underline; min-height: auto; padding: 4px; }
  #endDetails { margin-top: 8px; }
  .endbtns { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; margin-top: 18px; }
  .endbtns button { border-radius: 10px; padding: 11px 18px; font-size: 14px; font-weight: 700; min-height: 44px; border: 0; display: inline-flex; align-items: center; gap: 7px; }
  .icon { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; flex: none; }
  .hidden { display: none !important; }
  .reveal-hidden { display: none !important; }   /* progressive onboarding — a tab/currency not yet unlocked for this new player */
  .toast { position: fixed; left: 50%; bottom: 28px; transform: translateX(-50%) translateY(8px); z-index: 70;
    background: var(--panel); color: var(--text); border: 1px solid var(--grid);
    padding: 12px 18px; border-radius: 12px; font-weight: 700; font-size: 14px; max-width: 90vw; text-align: center;
    box-shadow: 0 12px 32px rgba(0,0,0,.45); opacity: 0; transition: opacity .25s, transform .25s; pointer-events: none; }
  .toast b { color: var(--line); }
  .toast.show { opacity: 1; transform: translateX(-50%) translateY(0); pointer-events: auto; cursor: pointer; }   /* BUG-08: tappable to dismiss */
  /* fix C: in a live Rush the toast is pinned to the top of the chart (top set in JS); keep it wrapping + off the HUD edges. */
  /* launch-fix C3: shrink-wrap to the text (max-content) instead of the fixed left:50% box collapsing to ~50vw — at 320
     the stack hint was 160px wide / 7 lines / 155px tall; max-content makes it 2-3 lines so it can't swamp the zone. */
  .toast.rush-top { width: max-content; max-width: min(92vw, 360px); white-space: normal; }

  /* password gate (soft barrier — private beta) */
  .gate { position: fixed; inset: 0; z-index: 100; display: flex; align-items: center; justify-content: center; background: var(--bg); padding: 20px; }
  .gatebox { text-align: center; }
  .gate-title { font: 900 32px/1 ui-sans-serif, system-ui, sans-serif; letter-spacing: 2px; margin-top: 14px; }
  .gate-sub { color: var(--muted); margin: 8px 0 20px; font-size: 14px; }
  #gatePass { width: 240px; max-width: 72vw; padding: 12px 14px; border-radius: 10px; border: 1px solid var(--grid); background: var(--panel); color: var(--text); font-size: 16px; text-align: center; }
  #gatePass:focus { outline: none; border-color: var(--line); }
  .gate button { display: block; margin: 12px auto 0; background: var(--line); color: #06222e; border: 0; border-radius: 10px; padding: 12px 26px; font-weight: 800; min-height: 46px; }
  .gate-err { color: var(--red); font-size: 13px; min-height: 18px; margin-top: 10px; }

  /* ---------- RUSH (endless arcade) ---------- */
  .rushcard { position: relative; display: block; width: 100%; text-align: left; cursor: pointer; overflow: hidden;
    background: linear-gradient(135deg, #3a1d5e 0%, #1a1230 60%, #2a1040 100%);
    border: 1px solid #a06bff; box-shadow: 0 0 0 1px rgba(160,107,255,.25), 0 10px 30px rgba(120,50,220,.25); }
  .rushcard::before { content: ""; position: absolute; inset: 0; background:
    radial-gradient(circle at 85% 15%, rgba(255,209,102,.22), transparent 45%); pointer-events: none; }
  .rushcard .rc-badge { display: inline-block; font-size: 11px; font-weight: 900; letter-spacing: 1px; color: #1a1230;
    background: var(--gold); padding: 3px 9px; border-radius: 999px; }
  .rushcard .rc-title { font: 900 34px/1 ui-sans-serif, system-ui, sans-serif; letter-spacing: 3px; margin: 10px 0 4px;
    background: linear-gradient(90deg, #ffd166, #ff9de2, #a06bff); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
  .rushcard .rc-sub { color: #d9c9ff; font-size: 15px; font-weight: 500; line-height: 1.45; max-width: 520px; }
  .rushcard .rc-rule { margin-top: 7px; font-size: 12.5px; font-weight: 600; color: #ffcf9e; opacity: .92; }
  .rushcard .rc-cta { margin-top: 12px; display: inline-block; font-weight: 800; color: #1a1230; background: linear-gradient(90deg,#ffd166,#ffb347);
    padding: 10px 18px; border-radius: 12px; min-height: 44px; }
  /* Daily Rush card — a warm ember palette so it reads as its own (fair, competitive) mode next to free Rush */
  .rushcard.daily { margin-top: 12px; background: linear-gradient(135deg, #5e2f1d 0%, #2a1710 60%, #40211a 100%);
    border-color: #ff9d5c; box-shadow: 0 0 0 1px rgba(255,157,92,.28), 0 10px 30px rgba(220,110,50,.25); }
  .rushcard.daily::before { background: radial-gradient(circle at 85% 15%, rgba(255,120,60,.28), transparent 45%); }
  .rushcard.daily .rc-title { background: linear-gradient(90deg, #ffd166, #ff8a5c, #ff5a5a); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
  .rushcard.daily .rc-sub { color: #ffd8c2; }

  .rushbar { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin: 0 0 6px; padding: 8px 14px;
    background: linear-gradient(135deg, rgba(58,29,94,.55), rgba(26,18,48,.55)); border: 1px solid #6b4bb0; border-radius: 14px; }
  /* launch-fix Z: PRACTICE tag (round 1 of onboarding) — a full-width gold pill under the stats row */
  .rb-practice { flex: 1 1 100%; text-align: center; font-weight: 800; font-size: 12px; letter-spacing: .3px; color: #06220f;
    background: var(--gold, #ffd166); border-radius: 8px; padding: 4px 10px; margin-top: -4px; }
  /* launch-fix Z2 (F9): on a 320 phone keep the 🔥 COMBO stat out from under the fixed ⏸ pause button (top-right) */
  /* launch-fix Z3 (F9): the Z2 `padding-right:48px` never moved the COMBO cell — .rb-stats is flex NOWRAP with
     non-shrinking cells, so the row simply overflowed and 🔥 COMBO sat under the fixed ⏸ (266-306 at 320px). Real fix:
     cap the row so it can never reach the ⏸ zone, let the cells shrink, and collapse COMBO to a wordless "🔥 x3". */
  @media (max-width: 340px) {
    .rushbar .rb-stats { max-width: calc(100% - 46px); gap: 4px; }
    .rushbar .rb-stat { flex: 0 1 auto; min-width: 0; }
    /* the cap alone can't help while the cells' min-content still exceeds it — so take real width out of the row: the
       Bank/Stack value slack (4.9em was slack for "$48.3k", 4.4em still fits it) and the "Combo" word. */
    /* (the Bank/Stack width trim lives in the Z3 narrow-screen block at the END of this file — the ≤360 block below
       re-set it to 4.9em at equal specificity.) */
    .rushbar .rb-combo { flex-direction: row; align-items: center; gap: 2px; }
    .rushbar .rb-combo .rb-lbl { display: none; }
    .rushbar .rb-combo::before { content: "🔥"; font-size: 12px; line-height: 1; }
    .rushbar .rb-combo b { font-size: 13px; }
  }
  /* launch-fix Z2 (F11): don't accept a tap on a modal's buttons until its entrance animation settles, so a tap during
     the pop-in (which scale/translates them) can't miss. revive3-followup (2): cut the blanket arm from 0.42s to 0.15s —
     0.42s silently ate the FIRST real tap on #reloadModal (players tapped twice). 0.15s still blocks the opening tap's
     instant synthetic click, but a deliberate tap ≥160ms now confirms. Rush Over keeps its longer 0.9s arm (below). */
  .adbox button, .endbox button { animation: btnArm 0s linear .15s forwards; pointer-events: none; }
  @keyframes btnArm { to { pointer-events: auto; } }
  /* revive3-followup (2): the Reload modal shows the brief arm as a dim→solid state, and every modal button gets a
     pressed state, so a tap is never silent. */
  #reloadModal .adbox button { animation: rlArm .15s linear forwards; }
  @keyframes rlArm { from { opacity: .72; pointer-events: none; } to { opacity: 1; pointer-events: auto; } }
  .adbox button:active, .endbox button:active { transform: translateY(1px); filter: brightness(.9); }
  /* launch-fix Z3 (Live b): RUSH OVER opens ~70ms after a run-ending CLOSE, with "New run" sitting just above where the
     finger already is. Give that card a longer 0.9s arm so a nervous second tap can't start a run before it's been read. */
  #rushOver .endbox button { animation-delay: .9s; }
  /* launch-fix Z3 (Live d): the fixed ⏸ sat over the RUSH OVER card's top-right corner. The card carries its own exits,
     so hide ⏸ while it's up. */
  body:has(#rushOver:not(.hidden)) #menuBtn { display: none; }
  /* the five stats stay on ONE row and each value sits in a FIXED-WIDTH, LEFT-aligned box (the $ lines up
     under its label), tabular digits — so a ticking price changes only what's inside its own box and never
     nudges Round or Lives. No clipping, so the lives are always visible. */
  .rushbar .rb-stats { display: flex; align-items: center; gap: 13px; flex-wrap: nowrap; flex: 0 1 auto; min-width: 0;
    font-variant-numeric: tabular-nums; }
  .rushbar .rb-stat { display: flex; flex-direction: column; line-height: 1.1; flex: 0 0 auto; }
  .rushbar .rb-lbl { font-size: 10px; letter-spacing: .5px; text-transform: uppercase; color: #b9a6e6; white-space: nowrap; }
  .rushbar .rb-stat b { font-size: 17px; font-weight: 800; white-space: nowrap; display: inline-block; text-align: left; }
  .rushbar #rushBanked, .rushbar #rushStackV { width: 4.6em; }
  .rushbar #rushPrice { width: 5.9em; }              /* fits $9,999.99 */
  .rushbar #rushDepth { width: 1.6em; }              /* just the number — the label already says "Round" */
  .rushbar #rushStrikes { width: auto; display: inline-flex; gap: 1px; }
  .rushbar #rushStrikes .rlife { display: inline-block; transform-origin: 50% 60%; }
  .rushbar #rushStrikes .rlife.lost { filter: grayscale(1) brightness(.9) opacity(.85); }
  .rushbar #rushStrikes .rlife.pop { animation: rlifePop .34s ease-out; }
  .rushbar #rushStrikes .rlife.burning { animation: rlifeBurn .8s cubic-bezier(.4,0,.5,1) forwards; }
  @keyframes rlifeBurn {
    0%   { transform: scale(1)    rotate(0);      filter: none; }
    12%  { transform: scale(1.6)  rotate(-9deg);  filter: brightness(1.8) saturate(1.7) drop-shadow(0 0 8px #ff5a5a); }
    26%  { transform: scale(1.2)  rotate(8deg);   filter: brightness(1.4) drop-shadow(0 0 11px #ff8a3d); }
    44%  { transform: scale(1.35) rotate(-6deg);  filter: brightness(1.2) drop-shadow(0 0 13px #ffb03d); }
    100% { transform: scale(.12)  rotate(30deg) translateY(11px); filter: brightness(.5); opacity: 0; }
  }
  @keyframes rlifePop { 0% { transform: scale(0); opacity: 0; } 60% { transform: scale(1.28); } 100% { transform: scale(1); opacity: 1; } }
  /* qa-polish (8e): the shield shatter. A 🛡️ lands over the pip the hit was aimed at, a crack flashes across it,
     then the two halves break apart — 560ms end to end. It lives in #fx and is placed in viewport coords over the
     pip (see _shieldShatter), so the HUD gains no node and cannot shift; left/top are the pip's CENTRE and every
     child is translated around it. The pip itself is never touched, so the life count keeps reading 3/3 — which is
     the true state, and the point of the effect. */
  .rshield-break { position: absolute; width: 0; height: 0; pointer-events: none; z-index: 2; }
  .rshield-break i, .rshield-break u { position: absolute; left: 0; top: 0; font-style: normal; text-decoration: none;
    will-change: transform, opacity; }
  .rshield-break i { font-size: 19px; line-height: 1; }
  .rshield-break i::before { content: "🛡️"; }
  /* the two halves, clipped left and right of centre so they read as one shield splitting rather than two shields */
  .rshield-break i:nth-of-type(1) { clip-path: inset(0 50% 0 0); animation: shBreakL .56s cubic-bezier(.3,.6,.35,1) forwards; }
  .rshield-break i:nth-of-type(2) { clip-path: inset(0 0 0 50%); animation: shBreakR .56s cubic-bezier(.3,.6,.35,1) forwards; }
  /* the crack: a thin bright diagonal that flashes across the shield just before it splits */
  .rshield-break u { width: 2px; height: 22px; border-radius: 2px; background: linear-gradient(180deg, rgba(255,255,255,0), #fff 30%, #fff 70%, rgba(255,255,255,0));
    box-shadow: 0 0 8px rgba(255,255,255,.9); opacity: 0; animation: shCrack .56s ease-out forwards; }
  @keyframes shBreakL {
    0%   { opacity: 0; transform: translate(-50%,-50%) scale(.55); }
    16%  { opacity: 1; transform: translate(-50%,-50%) scale(1.18); }
    42%  { opacity: 1; transform: translate(-50%,-50%) scale(1); }
    100% { opacity: 0; transform: translate(-128%,-104%) rotate(-40deg) scale(.86); }
  }
  @keyframes shBreakR {
    0%   { opacity: 0; transform: translate(-50%,-50%) scale(.55); }
    16%  { opacity: 1; transform: translate(-50%,-50%) scale(1.18); }
    42%  { opacity: 1; transform: translate(-50%,-50%) scale(1); }
    100% { opacity: 0; transform: translate(26%,-104%) rotate(40deg) scale(.86); }
  }
  @keyframes shCrack {
    0%, 28% { opacity: 0; transform: translate(-50%,-50%) rotate(14deg) scaleY(.2); }
    38%     { opacity: 1; transform: translate(-50%,-50%) rotate(14deg) scaleY(1); }
    56%     { opacity: 0; transform: translate(-50%,-50%) rotate(14deg) scaleY(1); }
    100%    { opacity: 0; transform: translate(-50%,-50%) rotate(14deg) scaleY(1); }
  }
  /* reduced motion: the shield still appears and fades, but nothing travels, rotates or cracks */
  @media (prefers-reduced-motion: reduce) {
    .rshield-break u { display: none; }
    .rshield-break i:nth-of-type(1), .rshield-break i:nth-of-type(2) { clip-path: none; animation: shBreakFade .56s ease-out forwards; }
    .rshield-break i:nth-of-type(2) { display: none; }   /* unclipped, the two halves would stack into one bold glyph */
    @keyframes shBreakFade { 0% { opacity: 0; transform: translate(-50%,-50%); } 20%, 55% { opacity: 1; transform: translate(-50%,-50%); } 100% { opacity: 0; transform: translate(-50%,-50%); } }
  }
  .rushbar .rb-bank b { color: var(--gold); }
  .rushbar .rb-stackv.up { color: #6de0a0; } .rushbar .rb-stackv.dn { color: #ff9db0; } .rushbar .rb-stackv.flat { color: #c9b8ec; }   /* QA#3: neutral — at the gong / fresh round the stack is $0/$1,000, which is NOT a loss */
  .rushbar .rb-controls { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-left: auto; }
  .rushbar .rb-mode { font-weight: 900; letter-spacing: 1px; color: #ffd166; font-size: 14px; cursor: pointer;   /* launch-fix Z: tappable for a what-does-this-mean tooltip */
    padding: 5px 12px; border: 1px solid rgba(255,209,102,.4); border-radius: 999px; background: rgba(255,209,102,.08); white-space: nowrap; }
  /* leverage selector: pick your risk for the next trade; locks (dims) while a position is open */
  .rushbar .rb-lev { display: flex; align-items: center; gap: 6px; }
  .rushbar .levbtn { min-width: 44px; min-height: 44px; padding: 5px 8px; border-radius: 9px; border: 1px solid #4b3a70;
    background: #241638; color: #c9b8ec; font-weight: 800; font-size: 13px; }   /* QA#10: ≥44×44 tap target */
  .rushbar .levbtn.on { background: linear-gradient(90deg,#ffd166,#ffb347); color: #1a1230; border-color: #ffd166; box-shadow: 0 0 12px rgba(255,196,74,.5); }
  .rushbar .levbtn.forced { background: linear-gradient(90deg,#ff9a3c,#ff5a3c); color: #1a1230; border-color: #ff8a3c; box-shadow: 0 0 14px rgba(255,120,50,.7); animation: levPulse .7s ease-in-out infinite; }
  @keyframes levPulse { 0%,100% { box-shadow: 0 0 12px rgba(255,120,50,.6); } 50% { box-shadow: 0 0 20px rgba(255,120,50,.95); } }
  .rushbar .levbtn:disabled { opacity: .45; } .rushbar .levbtn.on:disabled, .rushbar .levbtn.forced:disabled { opacity: 1; }
  .rushbar .levbtn.locked { opacity: .3; filter: grayscale(.6); }   /* leverage tier not unlocked yet this round */
  .rushbar .levbtn.between, .rushbar .levbtn.on.between, .rushbar .levbtn.forced.between { opacity: .4; filter: grayscale(.5); box-shadow: none; animation: none; }   /* QA#5: between-round result card up → chips are dimmed + not tappable */
  .rushbar .levbtn.justunlocked { animation: levUnlock 2s ease-out; }
  @keyframes levUnlock { 0% { transform: scale(1); box-shadow: 0 0 0 rgba(255,196,74,0); } 15% { transform: scale(1.35); box-shadow: 0 0 22px rgba(255,196,74,.95); background: linear-gradient(90deg,#ffd166,#ffb347); color: #1a1230; } 60% { transform: scale(1.1); box-shadow: 0 0 14px rgba(255,196,74,.7); } 100% { transform: scale(1); box-shadow: 0 0 0 rgba(255,196,74,0); } }
  /* GD UX: Cash Out / Bank is a CYAN-BLUE pill with a 🏦 — deliberately distinct from the green/red ● CLOSE trade
     button (different colour family, icon, and row) so "bank my gains" never reads as "close my position". */
  .rushtp { min-height: 44px; padding: 8px 16px; border-radius: 11px; border: 2px solid rgba(180,236,255,.35); font-weight: 900; font-size: 14px;
    color: #042436; background: linear-gradient(90deg,#5ad1f0,#49a7ef); box-shadow: 0 0 14px rgba(90,170,240,.45); }
  .rushtp:disabled { background: #2a3550; color: #7688a8; box-shadow: none; border-color: rgba(255,255,255,.08); }
  .rushtp.nudge { animation: bankpulse 1.1s ease-in-out infinite; }   /* 🏦 "bank it?" — pulses when you're sitting on a big win */
  /* E10: pulse the glow only — NEVER transform:scale on the Cash Out hit target, which moved the button under the
     finger mid-tap and cost real taps. Box-shadow/opacity leave the 44×44 target perfectly still. */
  @keyframes bankpulse { 0%,100% { box-shadow: 0 0 14px rgba(90,220,150,.4); } 50% { box-shadow: 0 0 0 6px rgba(255,209,102,.5), 0 0 20px rgba(255,209,102,.6); } }
  @media (max-width: 560px) {
    /* Compact rush bar → more of the screen is chart. Three tight rows: stats · [mode + leverage] · Cash Out. */
    .rushbar { gap: 6px 8px; padding: 6px 12px; margin-bottom: 4px; }
    .rushbar .rb-stats { gap: 8px; width: 100%; justify-content: space-between; }
    .rushbar .rb-stat b { font-size: 15px; }
    .rushbar #rushBanked, .rushbar #rushStackV { width: 4.2em; }
    .rushbar #rushPrice { width: 5.4em; }
    .rushbar .rb-lbl { font-size: 9px; }
    .rushbar .rb-controls { width: 100%; margin-left: 0; gap: 8px; }
    .rushbar .rb-mode { font-size: 12px; padding: 4px 10px; }
    .rushbar .rb-lev { gap: 5px; flex: 1 1 auto; justify-content: flex-end; }
    .rushbar .rb-lev .rb-lbl { display: none; }        /* the ×N buttons speak for themselves */
    .rushbar .levbtn { min-width: 44px; min-height: 44px; font-size: 13px; padding: 4px 6px; }   /* QA#10: keep ≥44×44 even on the compact bar */
    .rushtp { flex: 1 1 100%; min-height: 44px; }      /* Cash Out on its own full-width row (≥44 tall) */
    /* QA#6: reserve the top-right corner for the fixed ⏸ Pause button (top:14 right:14, 40×40) so the LIVES stat
       at the right end of the first row never sits under it. */
    body.rush .rushbar .rb-stats { padding-right: 46px; }
  }
  /* Rush reclaims vertical space for the chart: the captured-in-run model makes the tool shelf and the
     stat grid redundant (capital/price/round/vies live in the rush bar, P&L on the chart badge). */
  body.rush .hud, body.rush #powerups, body.rush .light-row, body.rush #gameSub, body.rush #hint { display: none !important; }
  body.rush #gameScreen .topbar { margin-bottom: 2px; }
  /* segment progress: fills as the cursor crosses the slice; turns amber near the end (finish line incoming) */
  .rushprog { height: 5px; border-radius: 3px; background: rgba(255,255,255,.08); overflow: hidden; margin: 0 0 6px; }
  .rushprog > i { display: block; height: 100%; width: 0; background: linear-gradient(90deg,#5ad1f0,#3ad884); transition: width .1s linear; }
  .rushprog.ending > i { background: linear-gradient(90deg,#ffd166,#ff9e2c); }
  .rushprog.gong { animation: gongpulse .5s ease-in-out 0s 6; }   /* #9: the bar flashes red for the final ~3s warning */
  .rushprog.gong > i { background: linear-gradient(90deg,#ff6b81,#ff3b57); }
  @keyframes gongpulse { 0%,100% { box-shadow: 0 0 0 0 rgba(255,59,87,0); } 50% { box-shadow: 0 0 0 2px rgba(255,59,87,.55); } }
  @media (prefers-reduced-motion: reduce) { .rushprog.gong { animation: none; } }
  /* active-effect chips: a persistent read-out of what each captured bonus is doing, with a live countdown */
  .rushfx { position: absolute; top: 8px; right: 10px; left: auto; transform: none; display: flex; gap: 6px; flex-wrap: wrap;
    justify-content: flex-end; max-width: 58%; pointer-events: none; z-index: 24; }   /* #7: held-charge chips hug the top-right so they never sit on the centred desk taunt (#liveQuip) */
  .rushfx .rfx { font-size: 14px; font-weight: 700; color: #eaf6ff; background: rgba(16,26,48,.9); border: 1px solid rgba(90,209,240,.5);
    padding: 5px 12px; border-radius: 999px; white-space: nowrap; box-shadow: 0 2px 10px rgba(0,0,0,.4); animation: rfxIn .2s ease-out; }
  .rushfx .rfx b { color: #9fe8ff; font-weight: 800; }
  .rushfx .rfx.bad { border-color: rgba(255,120,140,.6); color: #ffd7dd; background: rgba(60,20,32,.9); } .rushfx .rfx.bad b { color: #ff9db0; }
  /* held charges (🛡️/🏦) — gold, dashed, no countdown → reads as inventory you're holding, not a running effect */
  .rushfx .rfx.held { color: #ffe6a6; background: rgba(52,40,12,.92); border: 1px dashed rgba(255,209,102,.75); font-weight: 800; box-shadow: 0 2px 10px rgba(120,90,0,.35); }
  @keyframes rfxIn { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
  @media (max-width: 640px) { .rushfx .rfx { font-size: 17px; padding: 6px 13px; } }
  /* 3-2-1-GO before a round: big centred count so you get a beat to read the new chart */
  .rushcount { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; z-index: 42; pointer-events: none;
    font: 900 96px/1 ui-sans-serif, system-ui, sans-serif; color: #fff; text-shadow: 0 6px 30px rgba(0,0,0,.6); }
  .rushcount.go { color: #6de0a0; }
  .rushcount.pop { animation: rushCountPop .42s ease-out; }
  @keyframes rushCountPop { 0% { opacity: 0; transform: scale(1.7); } 40% { opacity: 1; transform: scale(1); } 100% { opacity: .85; transform: scale(1); } }
  /* 🦈 Finn — sleek P&L shark (prototype — gated by the MASCOT flag / ?mascot=0). Colour = the tide. */
  .finn { display: block; width: 100%; height: auto; overflow: visible; }
  .finn .fk-body { fill: var(--sk, #4e7bb0); }
  .finn .fk-fin { fill: var(--sk-d, #38588a); }
  .finn .fk-belly { fill: var(--sk-l, #a6c6e8); opacity: .92; }
  .finn .fk-lateral { stroke: var(--sk-l, #a6c6e8); stroke-width: 1.4; opacity: .5; }
  .finn .fk-rim { stroke: #cdf3ff; stroke-width: 1.7; opacity: .5; }
  .finn .fk-gill path { stroke: var(--sk-d, #38588a); stroke-width: 2.2; stroke-linecap: round; opacity: .6; fill: none; }
  .finn .fk-brow { stroke: #0c1526; stroke-width: 2; stroke-linecap: round; opacity: .45; }
  .finn .fk-eye { fill: #0c1526; } .finn .fk-eyehi { fill: #eafff4; }
  .finn .fk-mouth { stroke: #0c1526; stroke-width: 2.2; stroke-linecap: round; fill: none; }
  .finn .fk-teeth { stroke: #fff; stroke-width: 1.6; stroke-linejoin: round; fill: none; }
  .finn .fk-xeye { display: none; } .finn .fk-xeye path { stroke: #0c1526; stroke-width: 2.6; stroke-linecap: round; fill: none; }
  .finn .fk-all { transform-box: fill-box; transform-origin: center; }
  .finn-feeding { --sk: #2fcf80; --sk-d: #1c9a5b; --sk-l: #93f0c0; }
  .finn-ready    { --sk: #4e7bb0; --sk-d: #38588a; --sk-l: #a6c6e8; }
  .finn-bleeding { --sk: #ef5f78; --sk-d: #c2384f; --sk-l: #ffb2c2; }
  .finn-wiped    { --sk: #6a7486; --sk-d: #49515f; --sk-l: #8a93a3; }
  .finn-wiped .fk-eye, .finn-wiped .fk-eyehi, .finn-wiped .fk-brow, .finn-wiped .fk-mouth, .finn-wiped .fk-teeth { display: none; }
  .finn-wiped .fk-xeye { display: block; }
  /* live: JUST a fin, patrolling a thin waterline strip ABOVE the chart (outside the plot — never over the price line) */
  .finnstrip { position: relative; width: 100%; height: 30px; min-height: 30px; flex: 0 0 auto; margin: 6px 0 2px; overflow: hidden; }
  .finnstrip::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: linear-gradient(90deg, transparent, rgba(90,209,240,.5) 20%, rgba(90,209,240,.5) 80%, transparent); }
  /* Finn's horizontal position is driven from JS = ROUND PROGRESS (left at the open → far edge at the gong), not an idle loop. */
  .finnstrip .finn { position: absolute; left: 10px; bottom: 1px; width: 50px; height: auto; filter: drop-shadow(0 2px 4px rgba(0,0,0,.4)); transition: left .25s ease-out; }
  .finnonly .fk-fin { fill: var(--sk); }
  .finnonly .fk-shadow { fill: var(--sk); opacity: .2; }
  .finnstrip.finn-feeding .finn { animation-duration: 4.5s; }
  .finnstrip.finn-bleeding .finn { animation-duration: 9s; }
  .finnstrip.finn-wiped .finn { animation: none; transform: scaleY(-1); opacity: .7; }
  /* 🦈 live-fin FX — LIGHT & NON-INTRUSIVE: all transforms ride the inner .fk-swim group so they never fight the
     horizontal patrol on .finn, and they stay inside the 30px strip ABOVE the chart — never over the price/line.
     The pivot is the group's own centre so wiggle/surge/flip rotate in place. State class = finn-streak (persistent);
     transient one-shots (combo / surge / flip) are toggled from JS and self-clear. Order matters: the one-shots come
     AFTER finn-streak so they win the .fk-swim animation while both are on the element. */
  .finnonly .fk-swim { transform-box: fill-box; transform-origin: center; }
  .finnstrip.finn-streak .finn { animation-duration: 3.6s; }                                 /* streak: a steady, confident glide */
  .finnstrip.finn-streak .fk-swim { animation: finBob 2.1s ease-in-out infinite; }
  .finnstrip.finn-combo .finn { animation-duration: 2.8s; }                                  /* combo: eager, faster patrol … */
  .finnstrip.finn-combo .fk-swim { animation: finWiggle .45s ease-in-out 3; }                /*        … plus a quick wiggle */
  .finnstrip.finn-surge .fk-swim { animation: finSurge .7s ease-out; }                       /* big win: a brief surge/pop */
  .finnstrip.finn-flip .fk-swim { animation: finFlip 1.2s ease-in-out; }                     /* wipe: knocked belly-up, then rights itself */
  @keyframes finBob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-2px); } }
  @keyframes finWiggle { 0%,100% { transform: rotate(0); } 25% { transform: rotate(-7deg); } 75% { transform: rotate(7deg); } }
  @keyframes finSurge { 0% { transform: scale(1); } 35% { transform: scale(1.28) translateY(-3px); } 100% { transform: scale(1); } }
  @keyframes finFlip { 0% { transform: scaleY(1) rotate(0); } 30% { transform: scaleY(-1) rotate(-12deg); } 70% { transform: scaleY(-1) rotate(8deg); } 100% { transform: scaleY(1) rotate(0); } }
  /* end-screen slots: the legacy static shark, tilted by tide. Scoped with :not(.finn-live) so these rules
     NEVER touch a kit Finn (svg.finn-live) mounted into the same slot — otherwise .finnslot.finn-wiped would
     flip the customised Finn upside-down and .finnslot .finn would force its width (B.2 §7.4). */
  .finnslot { display: flex; justify-content: center; margin: 2px 0 8px; }
  .finnslot .finn:not(.finn-live) { width: 176px; filter: drop-shadow(0 7px 12px rgba(0,0,0,.42)); }
  .finnslot-sm { display: flex; justify-content: center; margin: 4px 0 2px; }
  .finnslot-sm .finn:not(.finn-live) { width: 140px; filter: drop-shadow(0 5px 9px rgba(0,0,0,.4)); }
  .finnslot.finn-feeding .finn:not(.finn-live) { transform: rotate(-6deg); }
  .finnslot.finn-bleeding .finn:not(.finn-live) { transform: rotate(7deg); }
  .finnslot.finn-wiped .finn:not(.finn-live), .finnslot-sm.finn-wiped .finn:not(.finn-live) { transform: scaleY(-1); }
  .finnslot-count { display: none; }
  /* lobby: the player's idle kit Finn above the Rush card */
  .lobbyfinn { display: flex; justify-content: center; align-items: flex-end; min-height: 0; margin: 2px 0 10px; }
  .lobbyfinn:empty { display: none; }
  /* ux-review (A1): on a short phone the idle hero Finn (size 132) ate ~200px the play button needed to clear the fold —
     shrink it hard there (overrides the inline --finn-size mountLobbyFinn sets) + drop its margins, so #rushCard top <= 300. */
  @media (max-height: 680px) { #lobbyFinn .finn-stage { --finn-size: 54px !important; } #lobbyFinn { margin: 0; } .lobbyhook { margin: 6px 0 8px; } }
  /* locker-custom2 (5): on a very short phone (e.g. 320×568) the Play card's CTA sat at ~558px — below the tab bar
     (~497px) and the viewport. Reclaim the vertical budget: drop the idle greeter Finn entirely, shrink the hook + the
     Rush title, and tighten the card so "▶ Play today's Rush" is fully above the tab bar on first paint, no scroll. */
  @media (max-height: 600px) {
    #lobbyFinn { display: none; }
    .lobbyhook { font: 800 clamp(16px, 4.6vw, 20px)/1.15 ui-sans-serif, system-ui, sans-serif; margin: 2px 0 8px; }
    .rushcard.daily { margin-top: 8px; }
    .rushcard .rc-title { font-size: 25px; margin: 5px 0 3px; }
    .rushcard .rc-sub { font-size: 13.5px; line-height: 1.3; }
    .rushcard .rc-rule { margin-top: 4px; }
    .rushcard .rc-cta { margin-top: 8px; }
    .bigcard { padding: 12px 15px; margin-bottom: 10px; }
  }
  /* locker-custom2 (4): on a short phone (e.g. 320×568) the Locker's modal header chrome (YOUR LOCKER / Customize Finn /
     tagline) ate ~145px above the sticky Finn stage, pushing the first Pieces row far below the fold. Reclaim it: drop the
     label + tagline, shrink the name, tighten the sheet padding. (css/locker.css shrinks the stage + teaser to match.) */
  @media (max-height: 679px) {
    #finnModal .adlabel, #finnModal .adtag { display: none; }
    #finnModal .adname { font: 800 14px/1.1 system-ui, sans-serif; margin: 0 0 6px; }
    /* N3: --fl-pad is the single source of truth for this sheet's inset. css/locker.css bleeds the sticky stage
       row and the Done footer to the sheet's edges with negative margins; they used to hardcode -26px, so when
       this rule dropped the padding to 14 they overshot by 12px each side and the sheet became horizontally
       scrollable (measured: .fl-modalbox scrollWidth 285 vs clientWidth 273 at 320x568, and a sideways drag
       moved it 12px). Keyed on max-HEIGHT, which is why 393x852 was unaffected and 320x568 / 360x640 were not. */
    #finnModal .adbox { padding: 14px; --fl-pad: 14px; }
    #finnModal #finnModalClose { margin-top: 8px; }
  }
  @media (prefers-reduced-motion: reduce) { .finnstrip .finn, .finnstrip .fk-swim { animation: none !important; } }
  /* between-segment transition banner — covers the abrupt stock/scale change */
  .rushflash { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 6px; text-align: center; z-index: 40; background: radial-gradient(circle at 50% 45%, rgba(36,16,64,.86), rgba(11,10,24,.94));
    border-radius: 14px; animation: rushFlashIn .25s ease-out; overflow: visible; max-height: 100%; }
  /* launch3 fix D: NO overflow:hidden — the card must never clip the Finn or any line. In normal mode it fills
     #chartWrap (inset:0) and the content is compacted to FIT at show time (showRushFlash sizes the Finn + toggles
     .rf-compact); in review mode it sizes to its content and grows UP, capped at #chartWrap's top (max-height:100%). */
  .rushflash .rf-finn { overflow: visible; }   /* the Finn stage still shows its celebration fx inside the card */
  /* fix D: on short screens (320x568) tighten the gaps + fonts so the Finn + all the lines fit with no overlap. */
  @media (max-height: 620px) {
    .rushflash { gap: 2px; }
    .rushflash .rf-round { font-size: 24px; } .rushflash .rf-prec { font-size: 13px; margin: 1px 0 3px; }
    .rushflash .rf-cap { font-size: 14px; } .rushflash .rf-next { font-size: 13px; } .rushflash .rf-close { font-size: 11px; margin-top: 3px; }
    .rushflash .rf-tap { margin-top: 8px; padding: 8px 18px; font-size: 14px; }
  }
  /* launch3 fix D: .rf-compact (set by showRushFlash when #chartWrap is short, chartH < 360) — measured, so it wins
     over the viewport @media above and guarantees the lines fit a 320x568 card with no clip and no overlap. */
  .rushflash.rf-compact { gap: 2px; }
  .rushflash.rf-compact .rf-round { font-size: 22px; }
  .rushflash.rf-compact .rf-prec { font-size: 12px; margin: 1px 0 2px; }
  .rushflash.rf-compact .rf-cap { font-size: 13px; }
  .rushflash.rf-compact .rf-next { font-size: 12px; margin-top: 2px; }
  .rushflash.rf-compact .rf-close { font-size: 10px; margin-top: 2px; }
  .rushflash.rf-compact.review .rf-close { display: none; }   /* review + very short → drop the reassurance line last */
  /* qa-polish (8e): …but never when the shield saved a life. That line is not reassurance — it is the only thing
     on the card explaining why the round reads ✗ with all three lives still green, which is the exact confusion
     8e exists to remove. Keep it at 320 and drop the reassurance TAIL instead, so it costs one short line. */
  .rushflash.rf-compact.review.has-shield .rf-close { display: block; }
  .rushflash.rf-compact.review.has-shield .rf-closetail { display: none; }
  .rushflash .rf-close .rf-shield { color: #ffe6a6; font-weight: 800; }
  .rushflash.rf-compact .rf-tap { margin-top: 6px; padding: 7px 16px; font-size: 13px; }
  /* FEAT-03: during the end-of-round review the banner sits at the bottom and grows up over the review chart. */
  .rushflash.review { inset: auto 0 0 0; height: auto; max-height: 100%; min-height: 40%; justify-content: flex-end; padding-bottom: 12px; gap: 3px;
    background: linear-gradient(to top, rgba(11,10,24,.97) 52%, rgba(11,10,24,.6) 78%, rgba(11,10,24,0)); border-radius: 0 0 14px 14px; }
  .rushflash.review .rf-round { font-size: 22px; }
  .rushflash.review .rf-prec { margin: 0 0 2px; }
  .rushflash .rf-round { font: 900 30px/1 ui-sans-serif, system-ui, sans-serif; letter-spacing: 2px;
    background: linear-gradient(90deg,#ffd166,#ff9de2,#a06bff); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
  /* fix 7: a lost / flat round overrides the win gradient with a solid colour (✗ red / – muted). */
  .rushflash .rf-round.rf-lost { background: none; -webkit-text-fill-color: var(--red); color: var(--red); }
  .rushflash .rf-round.rf-flat { background: none; -webkit-text-fill-color: var(--muted); color: var(--muted); }
  .rushflash .rf-prec { font-size: 15px; font-weight: 900; color: var(--gold); margin: 2px 0 6px; letter-spacing: .3px; min-height: 18px; }
  .rushflash .rf-prec .rf-stars { color: var(--gold); letter-spacing: 2px; }
  .rushflash .rf-prec .rf-pct { font-size: 20px; }
  .rushflash .rf-prec .rf-info { font-size: 12px; color: var(--muted); opacity: .8; vertical-align: super; }   /* launch-fix Z: "tap me" hint on the precision line */
  .rushflash .rf-cap { font-size: 17px; font-weight: 800; color: #d9c9ff; }
  .rushflash .rf-next { font-size: 15px; color: #b9a6e6; margin-top: 4px; display: flex; align-items: center; gap: 6px; }
  .rushflash .rf-close { font-size: 12px; color: #ffb3c0; margin-top: 6px; min-height: 14px; }
  .rushflash .rf-tap { margin-top: 14px; font-size: 15px; font-weight: 800; color: #1a1230; background: linear-gradient(90deg,#ffd166,#ffb347); padding: 10px 22px; border-radius: 12px; animation: tapPulse 1.1s ease-in-out infinite; }
  /* E10: "Tap to continue" pulse — glow only, no scale, so the tap target under the finger never shifts. */
  @keyframes tapPulse { 0%,100% { box-shadow: 0 0 0 0 rgba(255,209,102,.0); opacity: .94; } 50% { box-shadow: 0 0 0 6px rgba(255,209,102,.3); opacity: 1; } }
  @keyframes rushFlashIn { from { opacity: 0; transform: scale(.94); } to { opacity: 1; transform: scale(1); } }
  /* LIQUIDATION: a full-chart red slam so it's unmistakable that the position was wiped and a life lost */
  .rushliqflash { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 8px; text-align: center; z-index: 44; pointer-events: none; border-radius: 14px;
    background: radial-gradient(circle at 50% 45%, rgba(190,20,40,.42), rgba(120,10,25,.66)); animation: rushLiqIn .5s ease-out; }
  .rushliqflash .rlq-big { font: 900 40px/1 ui-sans-serif, system-ui, sans-serif; letter-spacing: 2px; color: #fff;
    text-shadow: 0 0 18px rgba(255,60,80,.9), 0 3px 10px rgba(0,0,0,.6); animation: rushLiqPop .5s cubic-bezier(.3,1.4,.5,1); }
  .rushliqflash .rlq-sub { font-size: 17px; font-weight: 800; color: #ffd7dd; }
  .rushliqflash .rlq-sub b { color: #ff8a9a; }
  .rushliqflash .rlq-count { margin-top: 14px; font-size: 15px; font-weight: 800; letter-spacing: .5px; color: #ffb3bd; }
  @media (max-width: 560px) { .rushliqflash .rlq-big { font-size: 52px; } .rushliqflash .rlq-sub { font-size: 20px; } }
  @keyframes rushLiqIn { 0% { opacity: 0; } 12% { opacity: 1; } 100% { opacity: 1; } }
  @keyframes rushLiqPop { 0% { transform: scale(.3) rotate(-6deg); } 55% { transform: scale(1.15) rotate(2deg); } 100% { transform: scale(1) rotate(0); } }
  /* margin call: a leveraged position is about to be liquidated — loud heads-up so it's never a surprise */
  .rushwarn { position: absolute; top: 46px; left: 50%; transform: translateX(-50%); z-index: 30; white-space: nowrap;
    font: 800 15px/1 ui-sans-serif, system-ui, sans-serif; letter-spacing: .5px; color: #fff;
    background: rgba(220,40,60,.92); border: 1px solid #ff9db0; padding: 8px 16px; border-radius: 999px;
    box-shadow: 0 4px 18px rgba(220,40,60,.5); animation: rushWarnPulse .7s ease-in-out infinite; }
  @keyframes rushWarnPulse { 0%,100% { transform: translateX(-50%) scale(1); opacity: .96; } 50% { transform: translateX(-50%) scale(1.06); opacity: 1; } }
  @media (max-width: 640px) { .rushwarn { font-size: 18px; padding: 10px 18px; } }
  /* launch-fix Z3 (Live c): on a phone the margin call became a 54px banner sitting over a fifth of the chart, with no
     price-tag avoidance. At ≤400px it's a SLIM one-line strip pinned to the chart's top edge; _rushWarnAvoidTag() adds
     .low to drop it clear whenever the live price/P&L tag is in that top band. */
  @media (max-width: 400px) {
    /* (the slim-strip declarations live in the Z3 narrow-screen block at the END of this file — a later @media (560px)
       rule of equal specificity was overriding them here.) */
  }
  .rushwarn.low { top: auto; bottom: 52px; }   /* above #posBadge (bottom:10 + ~36 tall), so they never stack */
  .posbadge.lev { box-shadow: 0 0 0 1px #ffd166, 0 0 14px rgba(255,196,74,.55); }

  .rushbox { text-align: center; background: linear-gradient(135deg, #241040, #140a26); border: 1px solid #a06bff; }
  .rushGoTitle { font: 900 15px/1 ui-sans-serif, system-ui, sans-serif; letter-spacing: 3px; color: #ff9de2; }
  #rushOver #roDepth { font-size: 32px; margin: 2px 0 2px; letter-spacing: 1px; opacity: .92; }
  #rushOver #roDepth.loss { color: #ff6b81; }   /* launch-fix Z3 (F4): a $0 / wiped-out total goes red, matching the −100% */
  /* revive2-followup (6): the post-revive total as a small muted line under the board-score headline (one line, ellipsis at 320) */
  #rushOver .ro-revivednote { margin: 0 auto 2px; max-width: 100%; color: var(--muted); font-size: 12.5px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* the screen-record moment: a giant return % that explodes onto the card */
  .ropct { font: 900 clamp(46px, 15vw, 92px)/.98 ui-sans-serif, system-ui, -apple-system, sans-serif; letter-spacing: -2.5px;
    background: linear-gradient(180deg, #8dffbe, #2fcf80); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; color: transparent;
    filter: drop-shadow(0 0 36px rgba(58,216,132,.45)); margin: 4px 0 0; }
  .ropct.loss { background: linear-gradient(180deg, #ffb0bf, #ff6b81); -webkit-background-clip: text; background-clip: text; filter: drop-shadow(0 0 32px rgba(255,107,129,.4)); }
  /* launch-fix Z3 (F4): breakeven (+0%) is neither a gain nor a loss — neutral, not the green gain gradient. */
  .ropct.flat { background: none; -webkit-text-fill-color: #d7deea; color: #d7deea; filter: drop-shadow(0 0 20px rgba(215,222,234,.25)); }
  .ropct.show { animation: pctPop .62s cubic-bezier(.2,1.35,.35,1) both; }
  @keyframes pctPop { 0% { transform: scale(.25) rotate(-3deg); opacity: 0; } 55% { transform: scale(1.14) rotate(1deg); } 100% { transform: scale(1) rotate(0); opacity: 1; } }
  @media (prefers-reduced-motion: reduce) { .ropct.show { animation: none; } }
  /* ⚔️ DUEL — live "score to beat" bar during the run (shown only when answering a challenge) */
  .duelbar { display: flex; align-items: center; gap: 10px; margin: 8px 0 0; padding: 7px 12px; border: 1px solid var(--grid); border-radius: 10px;
    background: linear-gradient(90deg, rgba(255,107,129,.09), rgba(90,209,240,.07)); font-size: 12.5px; }
  .duelbar .db-head { white-space: nowrap; color: var(--muted); } .duelbar .db-head b { color: var(--text); }
  .duelbar .db-track { flex: 1; height: 8px; border-radius: 6px; background: var(--grid); position: relative; overflow: hidden; min-width: 60px; }
  .duelbar .db-track i { position: absolute; inset: 0 auto 0 0; width: 0; background: linear-gradient(90deg, #5ad1f0, #3ad884); border-radius: 6px; transition: width .25s ease; }
  .duelbar.behind .db-track i { background: linear-gradient(90deg, #ff9db0, #ff6b81); }
  .duelbar .db-stand { white-space: nowrap; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--red); }
  .duelbar.ahead .db-stand { color: var(--green); }
  /* ⚔️ DUEL — side-by-side result on RUSH OVER */
  .duelresult { display: flex; align-items: stretch; margin: 12px 0; border: 1px solid var(--grid); border-radius: 14px; overflow: hidden; }
  .duelresult .dr-side { flex: 1; padding: 13px 10px; text-align: center; background: var(--panel); }
  .duelresult .dr-side.win { background: rgba(58,216,132,.14); }
  .duelresult .dr-name { font-size: 12px; color: var(--muted); display: flex; gap: 5px; justify-content: center; align-items: center; }
  .duelresult .dr-score { font-size: 23px; font-weight: 900; margin-top: 3px; letter-spacing: .3px; }
  .duelresult .dr-round { font-size: 11px; color: var(--muted); font-family: "IBM Plex Mono", ui-monospace, monospace; margin-top: 2px; }
  .duelresult .dr-vs { display: flex; align-items: center; padding: 0 10px; font-weight: 900; color: var(--muted); background: var(--panel); border-left: 1px solid var(--grid); border-right: 1px solid var(--grid); }
  #rushOver #roRec { font-weight: 900; letter-spacing: 1px; color: var(--gold); margin-bottom: 4px; }
  .robank { color: #d9c9ff; font-size: 15px; margin-top: 6px; }
  .rochal { margin: 8px 0 0; padding: 9px 14px; border-radius: 12px; background: rgba(255,209,102,.12); border: 1px solid rgba(255,209,102,.4); color: #ffe6a6; font-size: 14px; font-weight: 600; }
  .grp-rankline { font-weight: 900; font-size: 16px; letter-spacing: .2px; color: #ffe6a6; }   /* #4 group end-screen rank move: "#before → #after · banked $X · 👑 #1 …" */
  .roprec { margin: 8px auto 2px; font-weight: 900; color: var(--gold); font-size: 17px; letter-spacing: .3px; }
  .roprec .roprec-pct { font-size: 23px; }
  .roprec .roprec-stars { letter-spacing: 3px; }
  .roprec .roprec-how { margin-top: 3px; font-weight: 700; font-size: 11.5px; letter-spacing: .2px; color: var(--muted); }   /* #10: how the stars are earned */
  .rogrid { margin-top: 6px; font-size: 20px; letter-spacing: 2px; line-height: 1; }   /* FEAT-26: the Wordle 🟩🟨🟥 round grid */
  .rosummary { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; margin-top: 12px; }
  .rosum-cell { background: rgba(160,107,255,.10); border: 1px solid rgba(160,107,255,.22); border-radius: 12px; padding: 9px 6px; }
  .rosum-cell label { display: block; font-size: 10px; letter-spacing: .6px; text-transform: uppercase; color: #b9a6e6; margin-bottom: 3px; }
  .rosum-cell b { font-size: 17px; font-weight: 800; color: #fff; }
  /* the α-earned headline stays on one line (its inner spans keep their own white-space:nowrap); the long
     "🦈 from the desk" bonus ticker drops to its own full-width line and WRAPS instead of overflowing/clipping
     the card (QA#5: it was cut on the left — "top tick +5" read as "p tick +5"). */
  .roearned { margin-top: 12px; font-weight: 800; font-size: 18px; color: var(--gold); display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 2px 6px; max-width: 100%; }
  .roearned .adtag { flex: 1 0 100%; max-width: 100%; white-space: normal; overflow-wrap: break-word; }
  /* QA#5: the card must scroll / have bottom room so the yellow primary button is never clipped. dvh tracks the
     real mobile viewport (browser chrome in), and the extra bottom padding keeps the last button off the edge. */
  /* rushover-bigfinn: the hero may use the full card; the result screen caps itself (rule below) and never scrolls. */
  #rushOver.ro-hero .endbox { max-height: 92dvh; padding-bottom: 12px; }
  /* QA#5: collapse any EMPTY coloured placeholder in the stats area (desk/duel strip, bank line, grids) so it
     never paints a stray square under the stars legend. */
  #rushOver .rochal:empty, #rushOver .robank:empty, #rushOver .roprec:empty,
  #rushOver .rosummary:empty, #rushOver .roearned:empty, #rushOver .ronextunlock:empty,
  #rushOver .roearned-more:empty, #rushOver .roearned-panel:empty { display: none; }   /* rushover-bigfinn */
  /* Phase C gating — the action buttons (Play again / Share / Leaderboard / Lobby) and the Watch-ad offer stay
     hidden (opacity-only, so the card height and the FLIP target don't move) until the reveal queue drains, then
     FADE up from translateY(30px). Reduced motion: an instant fade, no slide, identical final state. */
  #rushOver .ro-gated { opacity: 0; transform: translateY(30px); pointer-events: none; }
  #rushOver .ro-reveal { opacity: 1; transform: none; pointer-events: auto; animation: roBtnsIn .5s ease both; }
  @keyframes roBtnsIn { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: none; } }
  @media (prefers-reduced-motion: reduce) {
    #rushOver .ro-gated { transform: none; }
    #rushOver .ro-reveal { animation: none; }
  }
  /* rushover-bigfinn: the sticky CTA bar, the dead `--finn-size:116px` block (the later 700px rule always won) and the
     whole `@media (max-height:700px)` compaction are GONE. RUSH OVER is now two screens (.ro-hero / .ro-result): the hero
     has no buttons at all, and the result screen lays them out as a static grid inside a card that fits with no scroll.
     KEPT from before: the .ro-gated/.ro-reveal button gate, .ropct + pctPop, #roRec, .ro-revivednote, and the .9s btnArm. */
  /* revive3-followup (1): the "board score" label on a revived headline is a small inline tag so the number + label stay
     on one line (keeps #roDepth height == the non-revived headline). .lbl-short/.lbl-full toggle the CTA labels by size. */
  #rushOver #roDepth .ro-bslabel { font-size: 15px; font-weight: 600; opacity: .78; letter-spacing: 0; }
  #rushOver .endbtns .lbl-short { display: none; }

  /* ===== rushover-bigfinn · SCREEN 1 — the celebration ===== */
  #rushOver.ro-hero .rushbox { padding: 12px 14px; }
  #rushOver.ro-hero #roHead { display: flex; flex-direction: column; align-items: center; }
  #rushOver.ro-hero #roMascot { margin: 0; }                      /* keeps the 46px .cel-title band from finn-scenes.css */
  #rushOver.ro-hero #roMascot .finn-stage { --finn-size: 240px !important; }
  #rushOver.ro-hero .rushGoTitle { font-size: 17px; letter-spacing: 4px; }
  #rushOver.ro-hero #roRec { font-size: 13px; margin: 0 0 2px; }
  #rushOver.ro-hero #roPct { margin: 2px 0 0; }                   /* keeps the clamp(46px,15vw,92px) hero size */
  #rushOver.ro-hero #roDepth { font-size: 20px; margin: 4px 0 0; opacity: .92; }
  #rushOver.ro-hero #roHead .ro-revivednote { margin-top: 2px; }
  #rushOver.ro-hero #roHeroLine { display: block; font-size: 14px; font-weight: 600; color: var(--muted); margin-top: 4px; }
  #rushOver.ro-hero #roSub, #rushOver.ro-hero #roPrecision, #rushOver.ro-hero #roDuel,
  #rushOver.ro-hero #roBank, #rushOver.ro-hero #roSummary, #rushOver.ro-hero #roNextUnlock,
  #rushOver.ro-hero #roEarned, #rushOver.ro-hero #roEarnedMore, #rushOver.ro-hero #roEarnedPanel,
  #rushOver.ro-hero #roAdAlphaSlot, #rushOver.ro-hero #roPromoSlot,
  #rushOver.ro-hero .endbtns { display: none !important; }
  /* the Finn shrinks before anything else on a short screen */
  @media (max-height: 700px) {
    #rushOver.ro-hero #roMascot .finn-stage { --finn-size: 200px !important; }
    #rushOver.ro-hero #roPct { font-size: clamp(44px, 14vw, 72px); }
  }
  @media (max-height: 600px) {
    #rushOver.ro-hero #roMascot .finn-stage { --finn-size: 170px !important; }
    #rushOver.ro-hero #roPct { font-size: clamp(38px, 13vw, 64px); }
    #rushOver.ro-hero .rushGoTitle { font-size: 15px; }
  }

  /* ===== rushover-bigfinn · SCREEN 2 — the result (one screen, no scroll) ===== */
  #rushOver.ro-result .rushbox { position: relative; overflow: hidden; padding: 10px 14px 12px;
    max-height: calc(100dvh - 16px - env(safe-area-inset-top) - env(safe-area-inset-bottom)); }
  #rushOver.ro-details .rushbox { overflow-y: auto; }             /* only the OPEN Details panel may scroll */
  #rushOver.ro-result #roHeroLine { display: none; }
  #rushOver.ro-result #roHead { display: flex; flex-direction: row; align-items: center; justify-content: center; gap: 10px; }
  /* docked: no banner band needed. The celebration stage (.finn-celeb-stage) keeps overflow:visible so the Evolution
     banner + FX can paint over the HERO; on the result screen that same overflow inflated the card's scrollHeight by
     170-315px (phantom scroll that made _roFit compact everything). The celebration is finished by now, so clip it here. */
  /* qa-polish (6): clip the prop too. overflow:hidden on the slot did not contain the Trophy Lift prop because
     the kit stage paints outside the slot's padding box; clip-path on the stage bounds every child. The HERO
     celebration is untouched — this is scoped to .ro-result. */
  #rushOver.ro-result #roMascot { margin: 0; padding-top: 0; overflow: hidden; }
  #rushOver.ro-result #roMascot .finn-stage { clip-path: inset(0 round 10px); }
  #rushOver.ro-result #roMascot .finn-stage { --finn-size: 96px !important; }
  #rushOver.ro-result #roHeadText { display: flex; flex-direction: column; align-items: flex-start; text-align: left; min-width: 0; }
  #rushOver.ro-result .rushGoTitle { font-size: 11px; letter-spacing: 2px; text-align: left; }
  #rushOver.ro-result #roPct { font-size: clamp(34px, 10vw, 52px); margin: 0; }
  #rushOver.ro-result #roDepth { font-size: 15px; margin: 0; }
  #rushOver.ro-result #roDepth .ro-bslabel { font-size: 12px; }
  #rushOver.ro-result #roHead .ro-revivednote { margin: 1px 0 0; text-align: left; font-size: 11.5px; }
  /* qa-polish (6): NEW RECORD was absolutely positioned at top:2px, which put it ON the card border (3px below
     the box top) and 5px into "⚡ RUSH OVER". In flow it cannot touch either: it sits above the title with its
     own row, and #roHeroTop keeps them apart. */
  #rushOver.ro-result #roRec { position: static; transform: none; font-size: 11px; margin: 0 0 3px; line-height: 1.2; }
  #rushOver.ro-result #roHeroTop { padding-top: 8px; }
  #rushOver.ro-result #roSummary { display: flex; gap: 5px; margin: 6px 0 0; }
  #rushOver.ro-result #roSummary .rosum-cell { flex: 1 1 0; min-width: 0; padding: 4px 3px; }
  /* qa-polish-fix (F3): with 4 cells the row gives each value 71px at 393 and 54px at 320 — too narrow for a
     5-letter ticker plus a figure at any legible size. _fitSumCells adds this class only when 4+ cells actually
     overflow, turning the single row into two columns (~125px a value). Cell count and order are unchanged. */
  #rushOver.ro-result #roSummary.rosum-wrap { flex-wrap: wrap; }
  #rushOver.ro-result #roSummary.rosum-wrap .rosum-cell { flex: 1 1 calc(50% - 3px); }
  #rushOver.ro-result #roSummary label { font-size: 8px; letter-spacing: .3px; margin-bottom: 1px; }
  #rushOver.ro-result #roSummary b { display: block; font-size: 11.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  #rushOver.ro-result #roPrecision { margin: 4px 0 0; font-size: 12px; }
  #rushOver.ro-result #roPrecision .roprec-pct { font-size: 15px; }
  #rushOver.ro-result #roPrecision .roprec-how { display: none; }  /* the tiers legend is a tutorial, not a result */
  #rushOver.ro-result #roPrecision .rogrid { display: inline; margin: 0 0 0 6px; font-size: 13px; letter-spacing: 1px; }
  #rushOver.ro-result #roSub { margin: 3px 0 0; font-size: 11px; }
  #rushOver.ro-result #roDuel { margin: 4px 0 0; padding: 4px 8px; font-size: 11.5px; }
  #rushOver.ro-result .duelresult { margin: 4px 0 0; }
  #rushOver.ro-result .duelresult .dr-side { padding: 5px 6px; }
  #rushOver.ro-result .duelresult .dr-score { font-size: 15px; }
  #rushOver.ro-result .duelresult .dr-round { font-size: 9px; }
  #rushOver.ro-result #roNextUnlock { display: none; }             /* its bar is rendered again inside the Details panel */
  #rushOver.ro-result #roEarned { margin: 4px 0 0; font-size: 14px; }
  /* qa-polish-fix (F4): the streak line's in-card home, used only when the toast fits neither above nor below
     the card. Gold like the α it reports, a touch smaller so it reads as a rider on the earned line. */
  #rushOver #roEarned .ro-streak { color: var(--gold, #ffd166); font-size: .86em; font-weight: 700; }
  #rushOver.ro-result #roEarned .adtag { display: none; }          /* lives in the Details panel */
  #rushOver.ro-result .endbtns { position: static; margin: 6px 0 0; padding: 0; background: none;
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; }
  /* 40px, not the prompt's 38: revive2-followup and revive4-followup (3) both require a ≥40px tap target, and bigfinn's
     own H6 only asserts ≥38 — so 40 satisfies all three. The card still fits (verified at all four sizes). */
  #rushOver.ro-result .endbtns button { min-height: 40px; padding: 4px 4px; font-size: 12px; }
  #rushOver.ro-result #rushAgainBtn { grid-column: 1 / -1; }
  #rushOver.ro-result .endbtns .lbl-full { display: none; }
  #rushOver.ro-result .endbtns .lbl-short { display: inline; }
  /* the Details disclosure */
  #rushOver .roearned-more { display: inline-block; margin: 3px 0 0; padding: 4px 10px; min-height: 0; border: 0; border-radius: 8px;
    background: transparent; color: var(--muted); font: 700 11.5px system-ui, sans-serif; cursor: pointer; }
  #rushOver .roearned-panel { margin: 4px 0 0; text-align: left; }
  #rushOver .roearned-panel .nu-bar { margin-top: 6px; }

  /* compact order when the result screen still overflows: 1) end-reason line, 2) chip labels, 3) docked Finn, 4) round grid.
     Never a button, never #roPct, never #roDepth. (_roFit applies these in order.) */
  #rushOver.ro-result.ro-c1 #roSub { display: none; }
  #rushOver.ro-result.ro-c2 #roSummary label { display: none; }
  #rushOver.ro-result.ro-c3 #roMascot .finn-stage { --finn-size: 80px !important; }
  #rushOver.ro-result.ro-c4 #roPrecision .rogrid { display: none; }

  /* transition hero -> result (~450ms, transform + opacity only). scale(2.5) == 96 x 2.5 == the 240px hero size. */
  #rushOver #roMascot { transition: none; }
  #rushOver.ro-result #roMascot { animation: roDock .45s cubic-bezier(.2,.9,.25,1) both; }
  @keyframes roDock { from { transform: scale(2.5) translateY(18px); opacity: .55; } to { transform: none; opacity: 1; } }
  #rushOver.ro-result #roHeadText, #rushOver.ro-result #roSummary, #rushOver.ro-result #roPrecision,
  #rushOver.ro-result #roSub, #rushOver.ro-result #roEarned, #rushOver.ro-result .endbtns {
    animation: roRise .45s cubic-bezier(.2,.9,.25,1) both;
  }
  @keyframes roRise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
  @media (prefers-reduced-motion: reduce) {
    #rushOver.ro-result #roMascot, #rushOver.ro-result #roHeadText, #rushOver.ro-result #roSummary,
    #rushOver.ro-result #roPrecision, #rushOver.ro-result #roSub, #rushOver.ro-result #roEarned,
    #rushOver.ro-result .endbtns { animation: none; }
  }
  .rushwin { display: flex; gap: 6px; margin: 2px 0 10px; }
  .rushwin button { flex: 1; font: 700 12px system-ui, sans-serif; padding: 7px 6px; border-radius: 9px; cursor: pointer;
    border: 1px solid rgba(160,107,255,.28); background: rgba(160,107,255,.09); color: #c9b8f0; }
  .rushwin button.on { background: linear-gradient(90deg,#ffd166,#ffb347); color: #1a1230; border-color: transparent; font-weight: 800; }
  /* lobby footer: version + feedback (scoped class names to avoid conflicts) */
  .lobbyfoot { display: flex; align-items: center; justify-content: center; gap: 8px; margin: 22px 0 14px; padding-top: 12px; border-top: 1px solid var(--grid); font-size: 12px; color: var(--muted); }
  .lobbyfoot .lf-ver { font-family: "IBM Plex Mono", ui-monospace, monospace; letter-spacing: .3px; opacity: .85; }
  .lobbyfoot .lf-dot { opacity: .5; }
  .lobbyfoot .lf-feedback { color: var(--muted); text-decoration: none; border-bottom: 1px dotted var(--grid); }
  .lobbyfoot .lf-feedback:hover { color: var(--line); border-bottom-color: var(--line); }

  /* ============================================================================
     SMALL-PHONE BREAKPOINTS (#13) — tune down from 480px to 400px and 360px.
     Appended LAST so, at equal specificity, these win by source order over the
     ≤480/≤560/≤640 rules above (the ≤400 block first, ≤360 after it, so the
     narrowest wins at 360). No new animations are introduced here, so the
     existing prefers-reduced-motion guards are untouched.
     (Plus one ≤560 overlay fix below for the margin-call banner, whose overflow
     spans the whole phone range, not just ≤400 — see its comment.)
     ============================================================================ */

  /* ---- chart overlay: MARGIN-CALL banner. "⚠️ MARGIN CALL — SELL before
     you're liquidated!" is a ~495px white-space:nowrap one-liner, centred with
     left:50% + translateX(-50%), so it ran off BOTH edges and clipped unreadably
     on every phone from ~360px up to ~495px. Let it wrap to ~2 lines on a fixed,
     frame-safe width. An explicit width (not max-width) is required: with left:50%
     and no width, shrink-to-fit only sees the right half and over-wraps to 4 lines.
     Scoped to 560px (the existing rush-compact breakpoint) so the whole affected
     range is fixed, not only the two new 400/360 breakpoints. ---- */
  @media (max-width: 560px) {
    .rushwarn { white-space: normal; width: min(300px, calc(100vw - 40px));
      font-size: 14px; line-height: 1.25; text-align: center; padding: 8px 14px; }
  }

  /* ---- ≤400px: narrow phones (iPhone SE/mini, small Androids) ---- */
  @media (max-width: 400px) {
    /* lobby RUSH card: the 34px/3px wordmark was near the edge — give it air */
    .rushcard .rc-title { font-size: 30px; letter-spacing: 2px; }
    .rushcard .rc-sub { font-size: 14px; }
    .rushcard .rc-rule { font-size: 12px; }
    .rushcard { padding-left: 16px; padding-right: 16px; }
    /* daily missions: keep the label + bar + progress on one comfortable line */
    .mrow { gap: 10px; }
    .mleft { gap: 9px; }
    .mlabel { font-size: 13px; }
    .memoji { font-size: 20px; }

    /* in-run RUSH HUD: reclaim width (less padding + tighter gaps) and shrink the
       stat values a touch so Bank/Stack (e.g. "$48.3k") never kiss the next stat */
    .rushbar { padding: 6px 9px; gap: 6px 8px; }
    .rushbar .rb-stats { gap: 6px; }
    .rushbar .rb-stat b { font-size: 14px; }
    .rushbar #rushBanked, .rushbar #rushStackV { width: 4.7em; }   /* slack for 6-char fmtK ($48.3k / $9,999) */
    .rushbar .rb-controls { gap: 6px 8px; }
    .rushbar .rb-mode { font-size: 11.5px; padding: 4px 9px; }
    /* (margin-call banner handled by the ≤560 block above) */
  }

  /* ---- ≤360px: the smallest phones (360×640/780). Tightest budget. ---- */
  @media (max-width: 360px) {
    /* lobby RUSH card */
    .rushcard .rc-title { font-size: 27px; letter-spacing: 1.5px; }
    .rushcard .rc-sub { font-size: 13.5px; }
    .bigcard { padding: 15px 15px; }
    .daily-hero { padding: 16px 16px; }
    .demoted { padding: 15px 15px; }
    /* daily missions */
    .mlabel { font-size: 12.5px; }
    .mprog { font-size: 11.5px; }

    /* RUSH HUD: one more step down. QA#10: the ×N leverage chips stay ≥44×44 even at the
       narrowest width so they remain comfortable (accessible) touch targets. */
    .rushbar { padding: 6px 7px; }
    .rushbar .rb-stats { gap: 5px; }
    .rushbar .rb-stat b { font-size: 13.5px; }
    .rushbar .rb-lbl { font-size: 8.5px; }
    .rushbar #rushBanked, .rushbar #rushStackV { width: 4.9em; }
    .rushbar .rb-controls { gap: 5px 7px; }
    .rushbar .rb-mode { font-size: 11px; padding: 4px 8px; letter-spacing: .5px; }
    .rushbar .rb-lev { gap: 4px; }
    .rushbar .levbtn { min-width: 44px; min-height: 44px; font-size: 12.5px; padding: 4px 5px; }
    .rushbar .rushtp { font-size: 13px; }
  }

  /* ===================== Finn avatar: profile centerpiece + Locker ===================== */
  .pfinnrow { width: 100%; display: flex; flex-direction: column; align-items: center; gap: 9px; margin-bottom: 4px; }
  /* B.3: the kit Finn is 240–300px tall and sizes itself through .finn-stage, so let the slot grow with it.
     The legacy fixed height only applied to the old inline shark (svg.finn, not .finn-live). */
  .pfinn { min-height: 240px; display: flex; align-items: flex-end; justify-content: center; }
  .pfinn svg.finn:not(.finn-live) { height: 210px; width: auto; }
  .finnedit { background: rgba(255,255,255,.05); color: var(--text); border: 1px solid var(--grid); border-radius: 999px;
    padding: 8px 16px; font-size: 13px; font-weight: 700; cursor: pointer; min-height: 40px; }
  .finnedit:hover { border-color: var(--line); }
  /* prominent "create" affordance for anyone who hasn't built a Finn yet (new + existing accounts) */
  .finnedit-new { background: var(--line); color: #06222e; border-color: var(--line); font-size: 14px; padding: 10px 20px; min-height: 44px;
    box-shadow: 0 0 0 0 rgba(90,209,240,.5); animation: finnPulse 2.2s ease-out infinite; }
  @keyframes finnPulse { 0% { box-shadow: 0 0 0 0 rgba(90,209,240,.45); } 70% { box-shadow: 0 0 0 10px rgba(90,209,240,0); } 100% { box-shadow: 0 0 0 0 rgba(90,209,240,0); } }
  @media (prefers-reduced-motion: reduce) { .finnedit-new { animation: none; } }
  .finnhint { width: 100%; text-align: center; color: var(--muted); font-size: 11.5px; margin-top: -2px; }

  .finnbuild { margin-top: 10px; }
  .locker { display: flex; flex-direction: column; gap: 4px; }
  .locker-preview { display: flex; align-items: flex-end; justify-content: center; height: 180px; flex-shrink: 0; }
  .locker-preview svg.finn { height: 210px; width: auto; }
  .locker-body { text-align: left; max-height: 40vh; overflow-y: auto; padding-right: 4px; margin-top: 4px; }
  .lk-sec { font: 700 10.5px ui-monospace, Menlo, monospace; letter-spacing: 1.2px; text-transform: uppercase; color: var(--muted); margin: 13px 0 6px; }
  .lk-row { display: flex; flex-wrap: wrap; gap: 6px; }
  .lk-pill { background: rgba(255,255,255,.04); color: var(--text); border: 1px solid var(--grid); border-radius: 999px;
    padding: 6px 11px; font-size: 12.5px; font-weight: 600; cursor: pointer; display: inline-flex; flex-direction: column;
    align-items: center; line-height: 1.25; min-height: 34px; justify-content: center; }
  .lk-pill.on { background: var(--line); border-color: var(--line); color: #06222e; font-weight: 800;
    box-shadow: 0 0 0 2px var(--line), 0 3px 10px rgba(90,209,240,.4); }
  /* locked: signal unavailability WITHOUT opacity (opacity on the pill would dim its sublabel too,
     and a child can't opt back out of a parent's opacity) — keeps the "🔒 …" requirement AA-legible */
  .lk-pill.locked { background: rgba(255,255,255,.02); border-style: dashed; border-color: var(--grid); color: var(--muted); cursor: default; }
  .lk-sub { font-size: 11.5px; color: var(--muted); opacity: 1; margin-top: 3px; font-weight: 600; letter-spacing: 0; }
  .lk-pill.locked .lk-sub { color: var(--muted); }
  .lk-save { margin-top: 16px; width: 100%; background: var(--green); color: #06240f; border: 0; border-radius: 12px;
    padding: 12px; font-size: 15px; font-weight: 800; cursor: pointer; min-height: 48px; }
  #wcFinnGo { margin-top: 14px; width: 100%; background: var(--line); color: #06222e; border: 0; border-radius: 12px;
    padding: 12px; font-size: 15px; font-weight: 800; cursor: pointer; min-height: 48px; }

  /* a Finn thumbnail wherever it rides a leaderboard / group / duel row */
  .finnpic { display: inline-flex; align-items: flex-end; vertical-align: middle; flex-shrink: 0; }
  .finnpic svg.finn { height: 52px; width: auto; }

  /* the customizable avatar replaces the legacy shark on the END screens — size it explicitly
     (higher specificity than the legacy `.finnslot .finn { width:176px }`) */
  .finnslot svg.finnx { width: auto; height: 200px; }
  #endFinn svg.finnx { width: auto; height: 150px; }
  #endFinn { justify-content: center; align-items: flex-end; margin: 4px 0 2px; }

  /* ==== launch-fix Z3 — narrow-screen overrides, intentionally LAST in the cascade ==========================
     These must out-rank earlier rules of EQUAL specificity that live in later media blocks (the ≤560px .rushwarn
     rule and the ≤360px #rushBanked width). Keep this section at the end of the file. */
  @media (max-width: 400px) {
    /* Live c: a SLIM one-line margin-call strip pinned to the chart's top edge, instead of a 37px centred banner
       covering ~a fifth of the chart. The ≤560 rule turns on wrapping + a 300px width — undo both. */
    .rushwarn { top: 6px; font-size: 12px; line-height: 1.2; padding: 4px 10px; letter-spacing: .2px;
      white-space: nowrap; width: auto; max-width: calc(100vw - 24px); }
    .rushwarn .warn-tail { display: none; }
    /* qa-polish (4c): the MARGIN CALL strip is pinned to the chart's top edge and the effect-chip row sits at
       top:8px right:10px, so at 320 the strip crossed the "📐 TA" chip by 38x23px — and QA saw MARGIN CALL + flash
       crash + 2x + a P&L float on screen together. The margin call outranks the chips: while it is up, the HELD
       one-shot charges step aside (they are a passive reminder and the HUD still carries them), and the live timed
       chips drop to the row below the strip so both stay readable. */
    body.rush.warn .rushfx .rfx.held { display: none; }
    body.rush.warn .rushfx { top: 34px; }
  }
  @media (max-width: 340px) {
    /* F9: take real width out of the stats row so 🔥 COMBO can never sit under the fixed ⏸. The row is flex NOWRAP, so
       what matters is its MIN-CONTENT, not the cap: trim the Bank/Stack value slack (4.9em was slack for "$48.3k";
       4.2em ≈ 57px still fits it at 13.5px) and tighten the gap. Measured: combo.right 279 → 256, ⏸ left 266. */
    .rushbar #rushBanked, .rushbar #rushStackV { width: 4.2em; }
    .rushbar .rb-stats { gap: 3px; }
  }

  /* ==========================================================================
     qa-polish (5): tap targets. Every control below measured under 40px in at
     least one axis; the brief's rule is EFFECTIVE hit area >= 40x40 at 320x568
     and 393x852, with no overlapping neighbours.

     Two techniques, chosen per element:
       - grow the box where there is room (toggles, sub-tabs, header chips);
       - keep the visual size and extend the hit area with a ::after pseudo
         element where growing would shift a tight layout (the no-scroll RUSH
         OVER card, the round card, the HUD mode pill).
     A pseudo hit area is useless inside an ancestor with overflow:hidden —
     .acctchip and .rankchip are exactly that, so those are grown instead.
     ========================================================================== */

  /* Revive: was a 284x14 div, now a real button. Still visually secondary to
     the Revive CTA — muted text, no fill, no border. */
  #rvDecline { display: block; width: 100%; min-height: 44px; margin-top: 10px;
    background: transparent; border: 0; cursor: pointer; font: inherit;
    color: var(--muted); font-size: 12px; -webkit-tap-highlight-color: transparent; }
  #rvDecline:focus-visible { outline: 2px solid var(--line); outline-offset: 2px; border-radius: 10px; }

  /* Reload: the INPUT's box becomes 40px and transparent; the visible 8px track
     is drawn by the track pseudo-elements so the slider still LOOKS the same.
     The notch stays centred on the track because the wrap still owns the width. */
  /* An input[type=range] with appearance:none still reserves ~2px around the track, so a declared 40px
     measured 38. Declare 44 and the box settles at >=40, which is what the hit-area rule is about. */
  .rlslider { height: 44px; padding: 0; background: transparent; border-radius: 0; box-sizing: border-box; }
  .rlslider::-webkit-slider-runnable-track { height: 8px; border-radius: 6px;
    background: linear-gradient(90deg, var(--gold), #e5556d); }
  .rlslider::-moz-range-track { height: 8px; border-radius: 6px;
    background: linear-gradient(90deg, var(--gold), #e5556d); }
  .rlslider::-webkit-slider-thumb { width: 28px; height: 28px; margin-top: -10px; }
  .rlslider::-moz-range-thumb { width: 28px; height: 28px; }

  /* Result card / round card / HUD: keep the visual size, extend the hit area.
     Each host needs position:relative so the pseudo anchors to it. */
  #rushOver .roearned-more, .rushflash .rf-prec, .rushbar .rb-mode { position: relative; }
  #rushOver .roearned-more::after, .rushflash .rf-prec::after, .rushbar .rb-mode::after {
    content: ''; position: absolute; left: 0; right: 0; top: 50%;
    height: 44px; transform: translateY(-50%); }
  /* qa-polish-fix (F5): "Details ▾" is the one host where the centred 44px area does not survive. Its box is 21px
     tall and "⚡ Play again" starts 6px below it, LATER in the DOM — so it paints over the bottom 5.5px and the
     effective area (elementFromPoint every 1px) measured 70x39, one pixel short of the 40px rule.
     The area is therefore anchored ABOVE centre instead of around it: 42px starting 24px up spans -24..+18, of
     which -24..+16.5 is unobstructed = 40.5px. Only the pseudo-element moves — no box, no margin and no card
     height changes, so the result card's no-scroll fit and its compaction class are untouched.
     Not solved by adding space between the rows: that grows the card, which is exactly what ro-result compaction
     is fighting at 320. */
  #rushOver .roearned-more::after { top: calc(50% - 24px); height: 42px; transform: none; }

  /* Room to grow: toggles, board sub-tabs, the scroll nudge, header chips. */
  .tgl { min-height: 40px; }
  .subtabs button { min-height: 40px; }
  .scrollHint { min-height: 40px; }
  .acctchip, .infobtn { min-height: 40px; }
  .infobtn { width: 40px; height: 40px; }
  @media (max-width: 719px) { .rankchip, .rchip { min-height: 40px; } }

  /* Locker colourway chips live in css/locker.css, which is linked AFTER this
     sheet and sets min-height:34px — the override has to go there, not here. */

  /* qa-polish-fix (F2): the effect-chip strip yields while a reward pill has nowhere else to sit (320-class screens,
     two-row strip). OPACITY ONLY — no display/visibility change — so the strip's layout and position are identical
     when it returns, and the ~150ms fade reads as a hand-off rather than a glitch. */
  .rushfx { transition: opacity .15s ease; }
  /* polish-fix2 (F2b): opacity alone left a LAYOUT RECT that still intersected the pill, so the overlap QA measures
     stayed non-zero even once the chips were invisible. The yielded strip is also translated clear of the chart.
     The transform is deliberately NOT transitioned: a gradual slide would sweep the rect across the pill and put the
     overlap back for ~150ms. Opacity still fades over 150ms, and because the strip is already out of frame that fade
     is what the eye reads as a hand-off. Transform never affects layout, so lifting the class restores the strip's
     position byte-for-byte. */
  /* chip-tag (Julien 2026-11-14, "fade, don't hop"): the price tag is in the row's only spot → the row reads through */
  .rushfx.rfx-fade { opacity: .25; transition: none; }   /* fades OUT at once (before the tag arrives), back IN over .15s */
  .rushfx.rfx-yield { opacity: 0; pointer-events: none; transform: translateY(-160%); }
  /* chip-tag (2026-11-14): a row parked LOW must not yield by sliding UP — that swept it through the middle of the chart,
     across the pill it was yielding to, while still fading (measured at 320: 67%→7% opacity over 1,387-1,802px²). It
     drops out of the bottom instead, and goes invisible at once, so nothing it passes is ever painted over. */
  .rushfx.rfx-low { transform: translateY(var(--rfx-dy, 0px)); }
  .rushfx.rfx-low.rfx-yield { transform: translateY(calc(var(--rfx-dy, 0px) + 160%)); transition: none; }

  /* qa-polish (8a): queued tips ride on the round card instead of pausing the tape or covering the Reload.
     Compact by design — a title and one line — so two of them cannot push the card past _rfFitCard's budget. */
  .rushflash .rf-tips { display: none; }
  .rushflash .rf-tips.has { display: flex; flex-direction: column; gap: 5px; margin: 6px 0 2px; width: 100%; }
  .rushflash .rf-tip { display: flex; flex-direction: column; gap: 1px; text-align: left;
    background: rgba(142,160,191,.10); border: 1px solid rgba(142,160,191,.22); border-radius: 10px;
    padding: 6px 9px; }
  .rushflash .rf-tip b { font: 800 12px/1.2 system-ui, sans-serif; color: var(--text); }
  .rushflash .rf-tip span { font: 600 11px/1.3 system-ui, sans-serif; color: var(--muted); }
  .rushflash.rf-compact .rf-tip { padding: 5px 8px; }
  .rushflash.rf-compact .rf-tip b { font-size: 11.5px; }
  .rushflash.rf-compact .rf-tip span { font-size: 10.5px; }

  /* qa-polish (8b): the carried stake + an opt-out into the full Reload. The button is >=40px and stops the card's
     own "tap anywhere to continue", so it can never be hit by accident while dismissing the card. */
  .rushflash .rf-stake { display: none; }
  .rushflash .rf-stake.has { display: flex; align-items: center; justify-content: center; flex-wrap: wrap;
    gap: 8px; margin: 4px 0 2px; font: 600 12.5px/1.2 system-ui, sans-serif; color: var(--muted); }
  .rushflash .rf-stake b { color: var(--text); font-weight: 800; }
  .rushflash .rf-adjust { min-height: 40px; padding: 8px 14px; border-radius: 999px; cursor: pointer;
    border: 1px solid rgba(142,160,191,.42); background: transparent; color: var(--text);
    font: 700 12.5px system-ui, sans-serif; -webkit-tap-highlight-color: transparent; }
  .rushflash.rf-compact .rf-stake.has { font-size: 11.5px; gap: 6px; margin: 3px 0 1px; }

  /* qa-polish (8f): the next-unlock hook on the +α line. One line, ellipsis rather than wrap, so the no-scroll
     result card keeps its compaction class. Never names a locked item — the teaser is name-safe by contract. */
  #rushOver #roEarned .ro-nuhint { color: var(--muted); font-weight: 700; white-space: nowrap; }
  #rushOver.ro-result #roEarned { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
