  /* Settings / Leaderboard / Currency-info / Shop popups — house frame.webp skin, same treatment
     as the hero card / item-detail / journey popup (see lobby.html .m-itemd-land/.m-journey-land).
     Unlike hero-main.js's other .m-look-overlay uses (created/removed from the DOM on demand,
     so the base display:flex is fine), these are static markup (always in the DOM, toggled via
     .open) -- give them their own hide-by-default so they don't all render at once. ANY new
     static .m-look-overlay modal MUST be added to BOTH lists below, or it renders open on
     load and its own .open-removing close button does nothing (confirmed bug, twice). */
  #settings-modal, #lb-modal, #promo-modal, #currency-info-modal, #store-modal, #gemaltar-modal, #google-modal, #quest2-modal, #chestpool-modal, #arena-modal, #arena-prize-modal, #mail-modal, #pack-modal{display:none}
  #settings-modal.open, #lb-modal.open, #promo-modal.open, #currency-info-modal.open, #store-modal.open, #gemaltar-modal.open, #google-modal.open, #quest2-modal.open, #chestpool-modal.open, #arena-modal.open, #arena-prize-modal.open, #mail-modal.open, #pack-modal.open{display:flex}
  /* The ARENA's two (2026-09-24) — the FOURTH time: both rendered open on load, the prize notice on
     top of everything, until a phone-viewport screenshot showed an empty leaf frame over the lobby.
     The prize notice paints above the Arena window (it can arrive while the window is open). */
  #arena-prize-modal{z-index:9002}
  /* chestpool-modal opens FROM INSIDE the shop (its "i" button, .m-store-info below) and must paint
     ABOVE it. Both share .m-look-overlay's z-index:9000 (hero-port.css), so with no override the tie
     falls back to DOM order -- and #store-modal is declared LATER in this file than #chestpool-modal,
     so it was winning and the info popup rendered underneath the shop it opened from. */
  #chestpool-modal{z-index:9001}

  /* ═══════ THE MAILBOX (2026-09-29) — redesign/mail/letter.webp, 720x1098 ═══════
     The art IS the window. Regions are measured off the art in percent of the box: the wooden plank
     (title) 26-74% x 4-13% y; the parchment between the envelope's flaps (paragraphs) 15-85% x
     16-57% y; the gift sits where the parchment still shows between the flaps (58-66% y), CLAIM on the
     envelope's front under its leaf seal. Height-driven so a landscape phone never crops it. */
  /* THE WHOLE HEIGHT (Roman, 2026-09-29: "bigger — over all the space we have from bottom to top"): the
     overlay's padding is cut to 5px for this window and the letter takes the rest. */
  #mail-modal{padding:5px}
  .m-mail-land{container-type:size;position:relative;height:calc(100vh - 10px);aspect-ratio:720/1098;
    background:url('mail/letter.webp') center/100% 100% no-repeat}   /* no drop-shadow: its paragraphs scroll, and a filter would redraw on every scroll frame (the 2026-09-29 performance pass) */
  .m-mail-close{position:absolute;top:1%;right:1%;width:13cqw;aspect-ratio:1;z-index:4;padding:0;border:none;
    background:url('heropopup/close.webp') center/contain no-repeat;font-size:0;cursor:pointer}
  .m-mail-close:hover{filter:brightness(1.12)}
  /* The speaker (mail.js toggleMailVoice): top-left, the X's mirror. Lit while Joe reads; pulses when the
     WebView wants a tap before it may start the sound (a letter opened over a running fight). */
  .m-mail-voice{position:absolute;top:2.2%;left:3%;width:10cqw;aspect-ratio:1;z-index:4;padding:0;cursor:pointer;
    border-radius:50%;border:.6cqw solid #c9a24a;background:#3a2412 center/62% no-repeat
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23ffe6a8'><path d='M3 9v6h4l5 4V5L7 9H3z'/><path d='M15.5 8.5a5 5 0 0 1 0 7' stroke='%23ffe6a8' stroke-width='2' fill='none' stroke-linecap='round'/><path d='M18 6a8.5 8.5 0 0 1 0 12' stroke='%23ffe6a8' stroke-width='2' fill='none' stroke-linecap='round'/></svg>")}
  .m-mail-voice.on{border-color:#ffe08a;background-color:#5a3a12}
  .m-mail-voice.ask{animation:mMailAsk 1.2s ease-in-out infinite}
  @keyframes mMailAsk{0%,100%{transform:scale(1)}50%{transform:scale(1.14)}}
  .m-mail-title{position:absolute;left:27%;right:27%;top:4.2%;height:8.4%;display:flex;align-items:center;justify-content:center;
    text-align:center;font-family:'Cinzel',serif;font-weight:900;font-size:4.6cqw;line-height:1.05;color:#fff0c8;
    text-shadow:0 2px 3px #000c;letter-spacing:.02em;overflow:hidden}
  .m-mail-body{position:absolute;left:15%;right:15%;top:16%;bottom:43%;overflow-y:auto;overscroll-behavior:contain;
    -webkit-overflow-scrolling:touch;color:#3a2814;font-family:Georgia,'Times New Roman',serif;font-size:4.1cqw;
    line-height:1.38;text-align:left}
  .m-mail-body p{margin:0 0 .8em}
  .m-mail-body .m-mail-link{margin-top:-.4em}
  .m-mail-body .m-mail-link a{color:#1b5fae;font-weight:700;text-decoration:underline;word-break:break-word}
  .m-mail-foot{position:absolute;left:0;right:0;top:57.5%;bottom:3%;display:flex;flex-direction:column;align-items:center}
  .m-mail-gift{display:flex;gap:4cqw;align-items:center;justify-content:center;height:8cqh;
    font-family:'Cinzel',serif;font-weight:900;font-size:6.2cqw;color:#5a3a12;text-shadow:0 1px 0 #fff8}
  .m-mail-gift-i{display:inline-flex;align-items:center;gap:1.6cqw}
  .m-mail-gift-i img{width:8cqw;height:8cqw;object-fit:contain}
  .m-mail-got{margin-top:6cqh;color:#ffe08a;text-shadow:0 2px 4px #000c;font-size:8cqw}
  .m-mail-note{max-width:70%;margin-top:.5cqh;text-align:center;font-size:3.3cqw;line-height:1.3;color:#7a1d10;font-weight:700}
  /* RIGHT UNDER THE GIFT (Roman, 2026-09-29: "the CLAIM button should be right under the 1000 GOLD, right
     there next to it") — it sat at the envelope's bottom edge, a hand's width away from what it claims. */
  .m-mail-claim{margin-top:.8cqh;width:46%;aspect-ratio:723/202;border:none;padding:0;cursor:pointer;
    background:url('heropopup/golden_button.webp') center/100% 100% no-repeat;font-family:'Cinzel',serif;font-weight:900;
    letter-spacing:.06em;font-size:5cqw;color:#3a1c08;text-transform:uppercase;display:flex;align-items:center;justify-content:center}
  .m-mail-claim:disabled{opacity:.5;cursor:default;filter:grayscale(.5)}
  .m-mail-claim:not(:disabled):hover{filter:brightness(1.1)}
  /* Shop's own frame (heropopup/shop/shop_frame.webp) -- the tall wood-bannered card, not the
     wide house frame.webp every other popup uses. Sizing recomputed for its real 1180/1402 ratio
     (was 1525/856) so the leaf/banner art is never stretched; width-driven like before since the
     shape is now portrait instead of landscape. */
  /* HEIGHT-driven, not width-driven -- this is a PORTRAIT box (1180/1402) now, so an unbounded
     width-first formula (the old wide-frame math) has no cap on the height it derives and runs off
     a landscape phone's short viewport top-and-bottom. Same shape of formula .m-store-land already
     uses successfully on this exact frame art, just a smaller vh cap since this popup's content is
     four short rows, not a scrolling catalog. */
  .m-settings-land{container-type:size;position:relative;
    height:min(900px,94vh,calc(64vw*1402/1180));aspect-ratio:1180/1402;
    max-width:none;max-height:none;width:auto;min-height:0;display:flex;flex-direction:column;
    padding:0;overflow:visible;text-align:center;
    background:url('heropopup/shop/shop_frame.webp') center/100% 100% no-repeat;
    border:none;border-radius:0;box-shadow:0 26px 80px #000d}
  /* Same corner placement as the Store's own close button on this same frame art (.m-store-close),
     nested into the frame's top-right corner instead of floating above it. */
  .m-settings-land .m-settings-close{position:absolute;top:-.4cqh;right:.4cqw;width:10.6cqw;
    height:auto;aspect-ratio:1;z-index:4;padding:0;border:none;border-radius:0;box-shadow:none;
    font-size:0;cursor:pointer;background:url('heropopup/close.webp') center/contain no-repeat}
  .m-settings-land .m-settings-close:hover{filter:brightness(1.12)}
  .m-settings-land .m-settings-title{position:static;flex:none;z-index:2;font-family:'Cinzel',serif;
    font-weight:900;letter-spacing:.05em;font-size:4.0cqw;color:#f0d78f;text-transform:uppercase;
    padding:3.4cqh 8cqw 0;text-shadow:0 2px 4px #000b,0 0 1.2cqw #ffd98a33}
  /* margin (not just padding) on top+bottom -- padding alone moves the CONTENT in from the edges,
     but the scrollable box itself (and therefore where overflow actually clips) still ran flush to
     the frame's own top/bottom border, so a scroll cut right at the frame's bottom edge with no
     breathing room. Margin shrinks the box itself, pulling the clip boundary in from both edges. */
  /* justify-content:flex-start, not center -- centering an overflowing flex column pushes part of
     its content ABOVE the visible top, and scrollTop can never go negative, so that pushed-up part
     (padding-top included) was unreachable. That's why padding-top had climbed to 19cqh and the
     first row still sat under the title: most of that padding was being centered away, not shown.
     flex-start makes padding-top behave like padding-top; reset to a sane value now that it isn't
     fighting the centering bug. */
  .m-settings-land .m-settings-content{position:static;flex:1;min-height:0;display:flex;
    flex-direction:column;align-items:center;justify-content:flex-start;gap:1.6cqh;
    margin:3.5cqh 0 2.5cqh;padding:3cqh 3cqw 6cqh;overflow-y:auto;
    /* No scroll anchoring: the in-game variant inserts a row at the TOP after layout, and anchoring
       would answer by scrolling down to keep the old first row in place -- the panel then opens in
       the middle. openSettingsMenu resets scrollTop on open; this stops later reflows undoing it. */
    overflow-anchor:none}
  /* Settings menu row -- button.webp, a dedicated icon-nav bar with its OWN octagon icon well
     baked into the left end (same gold-frame style as the icon medallions) and a chevron baked
     into the right end. Replaced two earlier misses: button_big.webp's corners were a flat JPEG
     with no alpha (solid white triangles instead of transparent), and quest_no_badge.webp has no
     icon well at all, so the icon had to float half-on/half-off its plain left edge. Base class
     stays a plain centered-text bar, because TWO other buttons reuse it with no icon (the Google
     sign-in fallback and the gift-picker's "Take this", both built at runtime in popups.js) --
     giving the icon its own modifier keeps those from inheriting padding sized for a well they
     don't have. */
  .m-settings-land .m-settings-item{position:relative;width:94%;aspect-ratio:722/118;
    border:none;padding:0;cursor:pointer;
    background:url('heropopup/settings/button.webp') center/100% 100% no-repeat;
    font-family:'Cinzel',serif;font-weight:800;letter-spacing:.04em;font-size:3.8cqw;
    color:#f0d78f;text-shadow:0 2px 3px #000b}
  .m-settings-land .m-settings-item:hover{filter:brightness(1.15)}
  .m-settings-land .m-settings-item:active{transform:scale(.97)}
  /* Icon variant -- the 4 real settings-menu rows only. Flex + left padding shifts the label clear
     of the bar's own baked-in icon well (measured off the source art: the well's dark socket runs
     roughly 0-16.6% of the bar's width). */
  .m-settings-land .m-settings-item-withicon{display:flex;align-items:center;justify-content:flex-start;
    padding:0 8% 0 19%}
  /* Sized to fill the bar's own icon well rather than straddle an edge -- the medallion's own gold
     octagon frame lands on top of the well's frame instead of floating beside a plain bar. */
  .m-settings-icon{position:absolute;left:2%;top:50%;transform:translateY(-50%);
    width:14%;height:auto;aspect-ratio:1;object-fit:contain;pointer-events:none;
    filter:drop-shadow(0 2px 4px #000a)}
  /* Settings -> Story (2026-09-28): one card per story video — the frame from the video, a play mark,
     its title; a locked one greyed with the reason under it. Built on open, removed on close (popups.js). */
  .m-story-list{gap:2.4cqh}
  .m-story-card{width:88%;display:flex;flex-direction:column;align-items:center;gap:1cqh;padding:0;border:none;
    background:none;cursor:pointer;font-family:'Cinzel',serif;color:#f0d78f;text-shadow:0 2px 3px #000b}
  .m-story-card:active{transform:scale(.98)}
  .m-story-thumb{position:relative;width:100%;aspect-ratio:16/9;border-radius:1.6cqw;overflow:hidden;
    border:.5cqw solid #c9a45a;box-shadow:0 1cqw 3cqw #000a}
  .m-story-thumb img{width:100%;height:100%;object-fit:cover;display:block}
  .m-story-play{position:absolute;left:50%;top:50%;width:14cqw;height:14cqw;transform:translate(-50%,-50%);
    border-radius:50%;background:#000a;border:.5cqw solid #f0d78f}
  .m-story-play:after{content:'';position:absolute;left:38%;top:26%;border-style:solid;border-color:transparent;
    border-width:3.6cqw 0 3.6cqw 5.6cqw;border-left-color:#f0d78f}
  .m-story-lock{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);font-size:9cqw}
  .m-story-card.locked{cursor:default}
  .m-story-card.locked .m-story-thumb img{filter:grayscale(1) brightness(.45)}
  .m-story-name{font-weight:800;font-size:3.6cqw;letter-spacing:.03em}
  .m-story-why{font-family:inherit;font-size:2.8cqw;color:#c0a0f0}
  /* Logout — same bar, red text instead of gold so it reads as destructive without needing a
     separate frame asset */
  .m-settings-land .m-settings-item-danger{color:#ff8a75}
  /* Performance section, injected below the 4 menu rows by _ensurePerfSection (popups.js) -- a
     title matching the other section labels in this kit, and 3 art buttons instead of the old
     flat CSS-gradient pills. */
  /* Shared by every injected settings section's title (Performance, Language) -- was two copies,
     one a real class and one an inline style on the Language div, which is why the same edit had
     to be made twice. One class now; text-transform:uppercase dropped since Language's own text
     (English/Русский/...) must not be forced through it. */
  .m-settings-sec-title{font-family:'Cinzel',serif;font-weight:900;letter-spacing:.05em;color:#f0d78f;
    font-size:5.6cqw;margin:1.4cqh 0 1cqh;text-shadow:0 2px 3px #000b}
  .m-perf-title{text-transform:uppercase}
  .m-perf-row{display:flex;align-items:flex-end;justify-content:center;gap:2.4cqw;width:94%}
  /* SOUND: a switch with its volume slider under it (2026-09-26). Each column is one switch + one slider,
     so the two stay paired whatever the row's width; cq units only, like every panel (the fixed-aspect rule). */
  .m-sound-col{flex:1;min-width:0;display:flex;flex-direction:column;align-items:stretch;gap:1.2cqh}
  .m-sound-col .m-perf-btn{flex:none;width:100%}
  .m-sound-vol{width:100%;height:4cqh;margin:0;accent-color:#f0c050;cursor:pointer}
  .m-sound-vol:disabled{opacity:.35;cursor:default}
  /* Unselected pill (performance_not_selected.webp, 231x75 native) and the selected one
     (performance_selected.webp, 228x91 -- its own diamond ornament pokes up above the SAME pill
     height, so its native height is taller by exactly the ornament). Explicit cqh heights instead
     of aspect-ratio -- aspect-ratio on a flex item that is ALSO a flex container for its own label
     computed the wrong size here (a nested-flex/aspect-ratio interaction, not a content bug), and a
     fixed height sidesteps it outright; the ~3:1 background stretch this implies is imperceptible
     on a flat-color pill. flex:1 + min-width:0 still divides the row's width evenly across all 3;
     align-items:flex-end on the row keeps every pill's BOTTOM level so only the taller selected
     button's diamond pokes up above the row, matching the source mockup. */
  .m-perf-btn{flex:1;min-width:0;position:relative;height:8.6cqh;border:none;padding:0;cursor:pointer;
    background:url('heropopup/settings/performance_not_selected.webp') center/100% 100% no-repeat}
  .m-perf-btn.on{height:10.4cqh;background-image:url('heropopup/settings/performance_selected.webp')}
  .m-perf-btn:active{transform:scale(.96)}
  /* Label as its own absolutely-positioned span, not the button's flex content -- percentage
     PADDING on a block always resolves against WIDTH even for padding-top/bottom (a CSS quirk),
     which made text drift off a short, wide button; percentage top/bottom on an absolutely
     positioned element correctly resolves against height, which is what centering here needs.
     top% differs per state because the two pills' native art puts their body in a different
     fraction of the TOTAL image height (91 vs 75 -- the diamond eats the top of the taller one). */
  .m-perf-label{position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);text-align:center;
    pointer-events:none;font-family:'Cinzel',serif;font-weight:900;letter-spacing:.03em;font-size:4.1cqw;
    color:#c8dde8;text-shadow:0 1px 2px #000a}
  .m-perf-btn.on .m-perf-label{top:59%;color:#fff8dc}
  /* LANGUAGE reuses the pill, but it has FIVE options where performance and orientation have three,
     and its labels are words rather than LOW/MED/HIGH. flex:1 divides the row evenly either way, so
     five pills are ~60% the width of three while the text is longer -- "Francais" at the shared
     4.1cqw label size overflows its pill. Only the two things that actually differ are overridden:
     a tighter gap to buy width back, and a label sized for the longest name. Everything else -- the
     art, the selected state, the diamond, the bottom alignment -- is inherited, which is the point. */
  .m-lang-row{gap:1.2cqw}
  .m-lang-row .m-perf-label{font-size:2.4cqw;letter-spacing:0;
    padding:0 .3cqw;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  /* Leaderboard variant: left-aligned scrollable list instead of a single centered button */
  .m-settings-land .m-lb-content{align-items:stretch;justify-content:flex-start;gap:.8cqh;
    padding:1.4cqh 6cqw 4cqh}
  /* Coupon-code variant: text input above the Redeem button */
  .m-settings-land .m-promo-content{gap:1.2cqh}
  /* Currency-info variant: icon + description, no separate close button (the X handles that) */
  .m-settings-land .m-currency-content{gap:2cqh}
  .m-currency-icon{width:20cqw;height:auto;object-fit:contain;filter:drop-shadow(0 3px 8px rgba(0,0,0,0.7))}
  .m-currency-desc{font-size:2.1cqw;color:#f0e4c0;line-height:1.55;font-family:'Cinzel',serif;padding:0 2cqw}
  .m-promo-input{width:94%;border:1px solid #6b5028;border-radius:1.2cqw;
    background:rgba(10,7,20,.6);color:#f0e4c0;font-family:'Cinzel',serif;font-size:2.6cqw;
    font-weight:700;letter-spacing:.08em;text-align:center;text-transform:uppercase;
    padding:1.1cqw 0;outline:none}
  /* Save-account variant: same frame as .m-promo-input, minus the uppercase transform -- that's
     fine for a redemption CODE but would visually mangle a password while typing it. */
  #m-save-form{display:flex;flex-direction:column;align-items:center;gap:.9cqh;width:100%}
  .m-save-or{font-size:1.3cqw;color:#8a93ad;text-align:center;text-transform:uppercase;letter-spacing:.05em}
  /* The save / log-in switch: a text link, not a second big button (2026-09-30). */
  .m-save-switch{background:none;border:0;padding:.4cqh 1cqw;font:inherit;font-size:1.3cqw;color:#e8c36a;
    text-decoration:underline;cursor:pointer}
  .m-save-input{width:94%;border:1px solid #6b5028;border-radius:1.2cqw;
    background:rgba(10,7,20,.6);color:#f0e4c0;font-family:'Cinzel',serif;font-size:2.2cqw;
    font-weight:700;letter-spacing:.04em;text-align:center;padding:1.1cqw 0;outline:none}
  .m-promo-input::placeholder{color:#8a7ab0;text-transform:none;letter-spacing:normal}
  .m-promo-input:focus{border-color:#d3ac5e}
  /* 3-way segmented control (e.g. Battle Screen orientation) */
  .orient-seg-btn{flex:1;padding:7px 2px;border:1px solid #4a3878;border-radius:8px;background:#241a3a;
    color:#b8a8d8;font-family:'Cinzel',serif;font-size:11px;font-weight:700;letter-spacing:0.3px;cursor:pointer;transition:0.15s}
  .orient-seg-btn.active{background:linear-gradient(180deg,#7a5cc0,#5a3ea0);color:#fff;border-color:#9a7ce0;
    box-shadow:0 0 8px rgba(150,120,224,0.5)}
  .orient-seg-btn:active{transform:scale(0.96)}

  /* Rank display */
  .m-rank-badge{display:flex;align-items:center;gap:5px;font-size:13px;font-weight:800;color:#f0c030;
    background:linear-gradient(180deg,#2a1e48,#1e1535);border:1px solid #3a2860;
    border-radius:14px;padding:4px 12px 4px 5px}
  .m-rank-icon{font-size:16px}

  /* Matchmaking overlay — stacked ON TOP of the already-open #m-event-panel (z-index:520),
     the same modal-over-modal z-index tier (550) used elsewhere in this file. */
  .m-event-queue-overlay{display:none;position:fixed;inset:0;z-index:550;flex-direction:column;
    align-items:center;justify-content:center;gap:1.2vh;
    background:radial-gradient(ellipse at center,#000000cc,#000000f0)}
  .m-event-queue-overlay.open{display:flex}
  /* Leaderboard row list — rendered by loadLeaderboard() inside .m-lb-content */
  .m-sub-empty{text-align:center;color:#c8b890;font-size:1.6cqw;padding:4cqh 1cqw;
    font-family:'Cinzel',serif;line-height:1.6}
  .m-lb-row{display:flex;align-items:center;gap:1cqw;padding:1cqh 1.2cqw;flex-shrink:0;
    background:linear-gradient(180deg,#1e1840,#160f2a);border:1px solid #3a286066;
    border-radius:1cqw}
  .m-lb-row.me{border-color:#c0a0f0;box-shadow:0 0 .8cqw #a080e044}
  .m-lb-rank{font-family:'Cinzel',serif;font-size:1.7cqw;font-weight:900;
    color:#f0c030;width:3.4cqw;text-align:center;flex-shrink:0}
  .m-lb-name{flex:1;font-size:1.7cqw;font-weight:700;color:#d0d4da;text-align:left}
  .m-lb-points{font-family:'Cinzel',serif;font-size:1.6cqw;font-weight:900;color:#c0a0f0;flex-shrink:0}
  /* Shop popup — house frame.webp skin, same treatment as the other ported popups. One continuous
     scroller (Gold & Gems, then Gear), not tabs. */
  /* Widened from the frame art's own 1122/1402 ratio (a mild stretch of shop_frame.webp, same
     tradeoff accepted for the Stash frame) to make real room for a wider, comfortable scrollbar in
     .m-store-body below -- the vw-based height term is recomputed for the SAME new ratio so the two
     don't drift apart on a width-constrained screen. */
  .m-store-land{container-type:size;position:relative;
    height:min(950px,94vh,calc(72vw*1402/1180));aspect-ratio:1180/1402;
    max-width:none;width:auto;max-height:none;display:flex;flex-direction:column;padding:0;overflow:visible;
    background:url('heropopup/shop/shop_frame.webp') center/100% 100% no-repeat;
    border:none;border-radius:0;box-shadow:0 26px 80px #000d}
  .m-store-close{position:absolute;top:-.4cqh;right:.4cqw;width:10.6cqw;height:auto;aspect-ratio:1;z-index:4;
    padding:0;border:none;border-radius:0;box-shadow:none;font-size:0;cursor:pointer;
    background:url('heropopup/close.webp') center/contain no-repeat}
  .m-store-close:hover{filter:brightness(1.12)}
  .m-store-title{flex:none;position:relative;z-index:2;text-align:center;font-family:'Cinzel',serif;
    font-weight:900;letter-spacing:.06em;text-transform:uppercase;font-size:5.6cqw;
    padding:3.4cqh 8cqw 0;color:#f0d78f;text-shadow:0 2px 4px #000b,0 0 1.2cqw #ffd98a33}
  /* Even left/right padding -- no scrollbar to clear anymore (hidden page-wide, see lobby.html);
     the wider right side used to be clearance for that rail's thumb. */
  .m-store-body{flex:1;min-height:0;overflow-y:auto;padding:0cqh 4cqw 16cqh 4cqw;position:relative;z-index:2}
  /* Current balance, ABOVE the first section title -- so "how much do I already have" is answered
     before the player even looks at what's for sale. Values are set on openStore() from
     accountData.gold/crystals and kept live by updateGoldDisplays/updateCrystalDisplays (same
     functions the topbar chips use), just against #m-shop-gold/#m-shop-crystals instead of
     #curGold/#curCrystals -- two independent displays of the same numbers, not a duplicate id. */
  .m-shop-balance{display:flex;align-items:center;justify-content:center;gap:2.4cqw;flex-wrap:wrap;
    margin:6cqh auto 0;width:100%;
    /* PINNED WHILE YOU SCROLL (Roman, 2026-09-28: "I reach what I want to buy and forget how many
       crystals I have"). Sticky inside .m-store-body; the band is the frame's own interior blue
       (sampled from shop_frame.webp) so the cards slide under it, fading out at its lower edge. */
    position:sticky;top:0;z-index:3;padding:1cqh 0 1.8cqh;
    background:linear-gradient(to bottom,rgb(6,33,62) 0,rgb(6,33,62) 78%,rgba(6,33,62,0) 100%)}
  /* Two wooden plank badges (currency_badge.webp), one per currency -- replaces the single dark pill.
     The image's own leaf-and-gold-rivet border does the framing; this element just sizes/positions
     the icon+number pair centered on top of it. */
  .m-shop-balance-badge{position:relative;flex:0 1 220px;max-width:44%;aspect-ratio:1278/305;
    background:url('heropopup/shop/currency_badge.webp') center/100% 100% no-repeat;
    display:flex;align-items:center;justify-content:center;gap:.7cqw;
    font-family:'Cinzel',serif;font-weight:900;font-size:4.6cqw;color:#fff3d6;text-shadow:0 1px 2px #000c}
  .m-shop-balance-badge .c-icon{width:1.3em;height:1.3em;margin:0;flex:none}
  /* PACKAGES (2026-09-28): the timed offer, first in the store — since 2026-09-29 a banner with the pack's
     island art that opens the pack WINDOW (below); the purchase happens there. */
  /* JUST THE PICTURE (Roman, 2026-09-29: "the picture is good — show only it, big, without that ugly
     frame; the buy button on the right and the time under it"). No box: the island art large, and a column
     on its right with the price and the clock. The picture opens the pack window; the price buys. */
  .m-pack-banner{margin:1cqh auto 0;width:94%;display:flex;align-items:center;gap:2cqw}
  .m-pack-banner img{width:62%;height:auto;flex:none;cursor:pointer}
  .m-pack-side{flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;gap:1.2cqh}
  .m-pack-timer{font-family:'Cinzel',serif;font-weight:900;font-size:3.6cqw;color:#ffd98a;white-space:nowrap;text-shadow:0 1px 2px #000c}
  .m-pack-buy{width:100%;font-size:5cqw}

  /* ═══════ THE PACK WINDOW (Roman, 2026-09-29: "ours is not pretty — look at Skull Hero's, like theirs") ═══════
     No frame: the parts float over the dimmed backdrop — the ribbon title (pack/ribbon.webp), the big
     "LIMITED OFFER" splash, the pack's island (pack/<id>_island.webp, generated from the pack's own item
     icons), the contents as rarity tiles, and a big yellow price button. Portrait box, height-driven so a
     landscape phone never crops it. Paints above the store it can be opened from. */
  #pack-modal{z-index:9003}
  .m-packpop{container-type:size;position:relative;height:min(94vh,900px);aspect-ratio:640/1000}
  .m-packpop-rib{position:absolute;left:0;right:0;top:0;aspect-ratio:900/254;display:flex;align-items:center;justify-content:center;
    padding:0 18% 3.4cqw;background:url('pack/ribbon.webp') center/100% 100% no-repeat;z-index:2}
  .m-packpop-rib span{font-family:'Cinzel',serif;font-weight:900;font-size:7.4cqw;line-height:1;color:#5a2a0a;
    text-shadow:0 .35cqw 0 #ffe9a0;white-space:nowrap}
  .m-packpop-close{position:absolute;top:-1.5cqw;right:0;width:12cqw;aspect-ratio:1;z-index:4;padding:0;border:none;
    background:url('heropopup/close.webp') center/contain no-repeat;font-size:0;cursor:pointer}
  .m-packpop-splash{position:absolute;left:3%;top:24%;z-index:3;display:flex;flex-direction:column;align-items:flex-start;
    transform:rotate(-8deg);transform-origin:left center;pointer-events:none}
  .m-packpop-splash span{font-family:'Cinzel',serif;font-weight:900;line-height:.95;color:#ffb21e;white-space:nowrap;
    -webkit-text-stroke:.5cqw #5a2a0a;paint-order:stroke fill;text-shadow:0 .7cqw 0 #5a2a0a}
  .m-packpop-splash span:first-child{font-size:10.5cqw}
  .m-packpop-splash span:last-child{font-size:8.5cqw}
  .m-packpop-time{position:absolute;right:3%;top:25%;z-index:3;padding:.6cqw 2.6cqw;border-radius:99px;background:#000a;
    border:.3cqw solid #ffb21e;font-family:'Cinzel',serif;font-weight:800;font-size:3.6cqw;color:#ffd98a;white-space:nowrap}
  .m-packpop-art{position:absolute;left:6%;width:88%;top:27%;height:44%;object-fit:contain;z-index:1}
  .m-packpop-items{position:absolute;left:3%;right:3%;top:72.5%;height:12.5%;display:flex;justify-content:center;gap:2.6cqw;z-index:2}
  .m-packpop-tile{position:relative;height:100%;aspect-ratio:1;border-radius:2.6cqw;border:.8cqw solid #231238;
    display:flex;align-items:center;justify-content:center;background:linear-gradient(180deg,#b9c2cf,#7d8796);
    box-shadow:inset 0 -1cqw 0 #0003,inset 0 .6cqw 0 #fff4}
  .m-packpop-tile.r-rare{background:linear-gradient(180deg,#72b9ff,#2f6fe0)}
  .m-packpop-tile.r-epic{background:linear-gradient(180deg,#c98eff,#7a3fe0)}
  .m-packpop-tile.r-legendary,.m-packpop-tile.r-gold{background:linear-gradient(180deg,#ffe07a,#f3a41b)}
  .m-packpop-tile img{width:80%;height:80%;object-fit:contain}
  .m-packpop-tile .n{position:absolute;left:0;right:0;bottom:3%;text-align:center;font-family:'Cinzel',serif;font-weight:900;
    font-size:4.2cqw;color:#fff;-webkit-text-stroke:.35cqw #3a1a05;paint-order:stroke fill}
  .m-packpop-buy{position:absolute;left:27%;right:27%;top:88%;height:9%;z-index:2;border-radius:2.4cqw;border:.6cqw solid #7a4a06;
    background:linear-gradient(180deg,#ffe066,#ffbf1f 60%,#f0a010);box-shadow:inset 0 .6cqw 0 #fff7,0 .9cqw 0 #7a4a06;
    font-family:'Cinzel',serif;font-weight:900;font-size:7cqw;color:#fff;-webkit-text-stroke:.45cqw #6a3a05;paint-order:stroke fill;cursor:pointer}
  .m-packpop-buy:disabled{filter:grayscale(.5);opacity:.7;cursor:default}
  .m-packpop-buy:not(:disabled):active{transform:translateY(.5cqw)}
  /* Section header ribbon (title1.webp), used above both Gold & Gems and Gear now that the shop
     is one continuous scroller instead of tabs. */
  .m-shoptitle{position:relative;width:68%;max-width:370px;margin:12px auto 0;
    aspect-ratio:313/93;background:url('heropopup/shop/title1.webp') center/100% 100% no-repeat;
    display:flex;align-items:center;justify-content:center;padding-top:5cqh;
    font-family:'Cinzel',serif;font-weight:900;letter-spacing:.06em;text-transform:uppercase;
    font-size:3.5cqw;color:#fff6e0;text-shadow:0 1px 2px #000a}
  /* Per-row color variants (the "six elements" title2-6/card2-6 kit) -- one color per Gear
     category so each row reads apart from the next at a glance. Gold & Gems keeps the original
     gold title1/card1 (no modifier needed). Paired by ACTUAL rendered color, not the source
     filenames' numbers -- title3.png (purple) and card3.png (wood) are NOT the same color despite
     matching numbers; the real pairs are title1+card1 (gold), title2+card2 (green),
     title3+card4 (purple), title4+card6 (blue), title5+card5 (red), title6+card3 (wood+blue-gem). */
  /* Rows since 2026-09-26: Items (helmet or armour) keeps the armour row's red, Weapons (with the
     shields) its blue, and Progress Stats takes the purple of the Helmets row it replaced. */
  .m-shoptitle-items{background-image:url('heropopup/shop/title_red.webp')}
  .m-shoptitle-weapon{background-image:url('heropopup/shop/title_blue.webp')}
  .m-shoptitle-stats{background-image:url('heropopup/shop/title_purple.webp')}
  .m-shoptitle-gems{background-image:url('heropopup/shop/title_wood.webp')}
  .m-store-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1cqw;row-gap:1.6cqh;
    width:100%;align-self:stretch}
  /* Real-money IAP cards, hidden for launch -- Roman, 2026-09-12: fully free for the first ~6
     months to build a player base, IAP comes back after. The cards stay in the DOM (not deleted)
     so re-enabling later is deleting this one rule, not re-authoring six cards. */
  .m-iap-hidden{display:none}
  /* Universal item-slot card -- the "six elements" kit's card1.webp, now used EVERYWHERE in the
     shop (Gold & Gems above and every Gear row: armor/weapons/helmets/shields/gems), replacing
     the old store_card_frame_gold.webp everywhere it was used. A small gem accent at top, a big
     glowing icon well through the middle, a wood footer bar at the bottom for the price button.
     Measured off the source PNG (178x224): border+gem 0-18%, the glow well 18%-78%, footer
     bar 78%-100%. */
  .m-store-card{position:relative;background:url('heropopup/shop/card1.webp') center/100% 100% no-repeat;
    border:none;border-radius:0;padding:19% 12% 3%;overflow:hidden;text-align:center;
    display:flex;flex-direction:column;align-items:center;transition:transform .12s;aspect-ratio:.795}
  .m-store-card:active{transform:scale(.95)}
  .m-store-card-items{background-image:url('heropopup/shop/card_red.webp')}
  .m-store-card-weapon{background-image:url('heropopup/shop/card_blue.webp')}
  .m-store-card-stats{background-image:url('heropopup/shop/card_purple.webp')}
  .m-store-card-gems{background-image:url('heropopup/shop/card_wood.webp')}
  .m-store-img{width:58%;aspect-ratio:1;margin:1.6cqh auto;object-fit:contain;display:block}
  /* The shadow under each store picture went 2026-09-29 (a filter per card, paid on every open and
     scroll); OLD = the FX switch (page-perf.js). */
  body.fx-legacy .m-store-img{filter:drop-shadow(0 3px 5px #0007)}
  .m-store-img[src*="gold-2"]{width:47%}
  .m-store-reward{font-size:2.5cqw;font-weight:700;color:#fff6e0;text-shadow:0 1px 2px #000a;padding:0;display:flex;
    align-items:center;justify-content:center;gap:.4cqw;white-space:nowrap}
  .m-store-reward .c-icon{width:1.5em;height:1.5em;margin-right:5px}
  .m-store-btn{display:block;margin-top:auto;width:100%;
    border:none;border-radius:0;background:none;box-shadow:none;
    font-family:'Cinzel',serif;font-size:3.5cqw;font-weight:900;letter-spacing:.02em;cursor:pointer;
    color:#fff3d6;text-shadow:0 1px 2px #000c;transition:transform .1s}
  .m-store-btn:active{transform:translateY(1px)}
  .m-store-btn-watch{background:none}
  /* Chest cards (Gear rows): a short description under the icon instead of a name badge, and a
     small "i" info button (top-right of the card) that lists every possible item the chest could
     roll -- see onShowChestPool() in popups.js. */
  .m-store-chestdesc{font-size:2.2cqw;line-height:1.25;color:#fff6e0;text-shadow:0 1px 2px #000a;
    margin:.2cqh 0}
  .m-store-info{position:absolute;z-index:3;top:8%;right:10%;width:7%;aspect-ratio:1;min-width:16px;
    border-radius:50%;border:none;cursor:pointer;padding:0;background:rgba(20,10,10,.55);
    box-shadow:inset 0 0 0 1px rgba(255,255,255,.4);color:#fff6e0;
    font-family:'Cinzel',serif;font-weight:900;font-style:italic;font-size:1.1cqw;line-height:1}
  /* Chest possible-items list popup (#chestpool-modal) -- icon + name grid, not plain text. */
  .m-chestpool-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px 8px}
  .m-chestpool-item{display:flex;flex-direction:column;align-items:center;gap:4px;text-align:center}
  .m-chestpool-icon{width:100%;aspect-ratio:1;object-fit:contain;border-radius:8px;
    background:rgba(255,255,255,.06);box-shadow:inset 0 0 0 1px rgba(255,255,255,.12)}
  .m-chestpool-name{font-size:11px;color:#c0b8de;line-height:1.2}
  .m-store-info:hover{background:rgba(20,10,10,.8)}
  /* Gear tab — 5 rows (armor/weapons/helmets/shields/gems), each a horizontally scrollable strip
     of .m-store-card (reused as-is, just narrower + fixed-width instead of the 3-col grid) so a
     curated handful per row doesn't need its own new card design. */
  .m-shopgear-section{margin-bottom:1.6cqh}
  .m-shopgear-section .m-shoptitle{margin-top:4cqh;margin-bottom:1.2cqh}
  .m-shopgear-row{display:grid;grid-template-columns:repeat(3,1fr);gap:1cqw;row-gap:1.6cqh;
    width:100%;padding:.2cqh 0 .3cqh}
  /* Four progress-stat cards (sword, bow, magic, HP) in one line. */
  /* 3 A ROW (2026-09-30): small / medium / large of each stat — the four stats become four rows. ONE picture
     size for all three (Roman: the pictures shrinking with the pack left the text and buttons out of line);
     the size lives in the ART instead — the items alone, a small pouch, the big bag (stat_<kind>_small /
     _medium, stat_<kind> for large). */
  .m-shopgear-stats{grid-template-columns:repeat(3,1fr)}
  .m-shopgear-stats .m-store-img{width:60%}
  .m-store-btn-ad{display:inline-flex;align-items:center;justify-content:center;gap:.6cqw}
  /* Inline currency icon — use anywhere text previously used 🪙 / 💎 emoji */
  .c-icon{width:1.15em;height:1.15em;object-fit:contain;vertical-align:-0.22em;margin-right:3px;
    display:inline-block;filter:drop-shadow(0 1px 1px rgba(0,0,0,0.35))}
  /* AP shop — vertical stack (icon + earn-label) auto-centered in the card */
  .m-ap-stack{display:flex;flex-direction:column;align-items:center;gap:16px;
    margin:auto 0}
  .m-ap-icon{width:60px;height:60px;object-fit:contain;flex-shrink:0;
    filter:drop-shadow(0 2px 3px rgba(0,0,0,0.4))}
  .m-placeholder-desc{font-size:14px;color:#6a5a8a;max-width:300px}

  /* Watch-ad daily quest row */
  /* Watch-ad row — same purple base as other quest rows but with a gold border
   * (the WATCH button is the eye-catcher, not the row chrome). */
  /* Watch-ad row uses the dedicated watchad banner (coins art baked on the left). */
  .m-quest-watchad{background:url('/sprites-opt/ui/season/watchad.webp') center / 100% 100% no-repeat!important;
    border:none!important;border-radius:0!important;box-shadow:none!important;
    aspect-ratio:1229/270;padding:0 14px 0 26%!important}
  /* Watch button uses the gold points_button sprite. */
  .m-quest-watchad-btn{flex-shrink:0;width:80px;aspect-ratio:415/152;height:auto;cursor:pointer;border:none;padding:0;
    background:url('/sprites-opt/ui/season/points_button.webp') center / 100% 100% no-repeat;
    font-family:'Cinzel',serif;font-weight:900;letter-spacing:1px;font-size:11px;
    color:#3a2400;text-shadow:0 1px 0 rgba(255,230,150,0.45);text-transform:uppercase;
    transition:transform 0.1s}
  .m-quest-watchad-btn:active{transform:scale(0.96)}
  .m-quest-watchad-btn.cooldown{filter:grayscale(0.6) brightness(0.55);cursor:not-allowed}
  /* ═══ Mobile Quest Sections — season-frame palette ═══ */
  /* Subtle frame; the season frame.webp is already doing the heavy lifting
   * around the whole modal. Drop the heavy blue/purple panel border so this
   * doesn't feel like a competing frame inside a frame. */
  .m-quest-section{border-radius:0;overflow:visible;
    box-shadow:none;background:transparent;border:none}
  .m-quest-section.daily{background:transparent;border:none}
  /* Section header row */
  .m-quest-section-header{display:flex;justify-content:space-between;align-items:center;
    padding:2px 0 8px;gap:10px}
  /* "DAILY" label uses the title_free.webp pill (same one as the FREE column header) */
  .m-quest-section-title{aspect-ratio:553/137;height:34px;
    background:url('/sprites-opt/ui/season/title_free.webp') center / 100% 100% no-repeat;
    display:flex;align-items:center;justify-content:center;
    font-family:'Cinzel',serif;font-size:13px;font-weight:900;letter-spacing:3px;
    color:#fff;text-shadow:0 2px 4px rgba(0,0,0,0.85);padding:0 18px;min-width:120px}
  /* "Resets daily" timer uses the duration.webp pill */
  .m-quest-timer-badge{aspect-ratio:346/74;height:30px;
    background:url('/sprites-opt/ui/season/duration.webp') center / 100% 100% no-repeat;
    display:flex;align-items:center;justify-content:center;gap:5px;
    font-family:'Cinzel',serif;font-size:10px;font-weight:800;letter-spacing:1.5px;
    color:#fff;text-shadow:0 1px 3px rgba(0,0,0,0.8);padding:0 14px}
  .m-quest-timer-badge::before{content:'⏱';font-size:11px}
  /* Quest rows — tightened so all 6 dailies fit inside the frame's visible
   * content area without scrolling past the bottom decoration. */
  .m-quest-list{display:flex;flex-direction:column;gap:5px;padding:0}
  .m-quest-item{display:flex;align-items:center;gap:10px;
    background:url('/sprites-opt/ui/season/quest_no_badge.webp') center / 100% 100% no-repeat;
    border:none;border-radius:0;box-shadow:none;
    aspect-ratio:1210/206;padding:0 14px 0 8px}
  /* Completed rows: same banner; the green check alone marks "done" (no glow ring). */
  .m-quest-item.done{opacity:1;box-shadow:none}
  /* Per-quest badge medallion — pops slightly above/below the row like the mockup.
     (Named -medal, NOT -badge: .m-quest-badge is the red notification dot.) */
  .m-quest-medal{flex-shrink:0;width:52px;height:52px;object-fit:contain;
    filter:drop-shadow(0 2px 4px rgba(0,0,0,0.6))}
  .m-quest-item-info{flex:1;min-width:0}
  .m-quest-name{font-family:'Cinzel',serif;font-size:12px;color:#f0e4c0;font-weight:800;
    letter-spacing:0.5px;line-height:1.15;
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
    text-shadow:0 1px 2px rgba(0,0,0,0.6)}
  .m-quest-progress-row{display:flex;align-items:center;gap:7px;margin-top:4px}
  .m-quest-bar{flex:1;height:6px;background:rgba(0,0,0,0.5);border-radius:3px;overflow:hidden;
    border:1px solid rgba(240,200,112,0.25)}
  .m-quest-fill{height:100%;border-radius:2px;transition:width 0.3s;
    background:linear-gradient(90deg,#f0c870,#ffe080)}
  .m-quest-pct{font-family:'Cinzel',serif;font-size:10px;color:#c0a0f0;font-weight:800;
    min-width:34px;text-align:right;text-shadow:0 1px 2px rgba(0,0,0,0.6)}
  /* Progress count under the quest name (progress bar removed). */
  .m-quest-count{font-family:'Cinzel',serif;font-size:11px;color:#c0a0f0;font-weight:800;
    margin-top:3px;letter-spacing:0.5px;text-shadow:0 1px 2px rgba(0,0,0,0.6)}
  /* Reward chip — uses the gold points_button sprite. */
  .m-quest-reward{font-family:'Cinzel',serif;font-size:10px;font-weight:900;text-transform:uppercase;
    color:#3a2400;white-space:nowrap;letter-spacing:0.5px;
    flex-shrink:0;width:64px;aspect-ratio:415/152;
    display:flex;align-items:center;justify-content:center;
    background:url('/sprites-opt/ui/season/points_button.webp') center / 100% 100% no-repeat;
    text-shadow:0 1px 0 rgba(255,230,150,0.5)}
  .m-quest-check{width:24px;height:24px;border-radius:50%;
    background:linear-gradient(180deg,#80e040,#408020);
    border:2px solid #1a3010;
    display:flex;align-items:center;justify-content:center;
    font-size:13px;font-weight:900;color:#fff;text-shadow:0 1px 0 rgba(0,0,0,0.4);
    flex-shrink:0}
  .m-craft-card{position:absolute;right:6px;bottom:20px;width:100px;max-width:30vw;z-index:6;cursor:pointer;transition:transform .1s;filter:drop-shadow(0 4px 11px rgba(0,0,0,.6))}
  .m-craft-card:active{transform:scale(0.93)}
  .m-craft-card img{width:100%;display:block}
  .m-craft-card-label{position:absolute;left:0;right:0;bottom:8%;text-align:center;color:#ffe6a0;font-family:Cinzel,serif;font-weight:800;font-size:11px;letter-spacing:1px;text-shadow:0 1px 3px #000,0 0 6px rgba(0,0,0,.85);pointer-events:none}
  /* Treasure box card — opposite corner from Craft. Uses the chest art (closed/open on tap). */
  .m-treasure-card{position:absolute;left:6px;bottom:26px;width:104px;max-width:30vw;z-index:6;cursor:pointer;transition:transform .1s;
    filter:drop-shadow(0 4px 11px rgba(0,0,0,.6))}
  .m-treasure-card:active{transform:scale(0.93)}
  .m-treasure-card .m-tc-img{width:100%;display:block}
  .m-treasure-card.hb-locked{filter:grayscale(1) brightness(.55)}
  .m-treasure-card.hb-locked::after{content:'🔒';position:absolute;top:3px;right:6px;font-size:15px;filter:none}
  /* Treasure stash grid (deposit/withdraw cells) -- a portrait card (icon / name / action button)
     instead of the old icon-only square with text crammed along the bottom edge. */
  /* min-width:0 on the cell is the actual fix for "3 per row without a sideways scrollbar" -- grid
     items default to min-width:auto, which stops a 1fr column shrinking past its CONTENT's natural
     size (an unbreakable name, an unconstrained icon) even though the track math says 1/3 each.
     Without it a wide-enough item silently pushes the grid past 100% and the row starts scrolling
     sideways instead of the card just getting smaller. */
  .m-tb-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:7px;margin-top:6px}
  .m-tb-cell{position:relative;min-width:0;aspect-ratio:3/4;border-radius:8px;border:2px solid #caa14e;
    background:linear-gradient(180deg,#2e2456,#1e183e);
    display:flex;flex-direction:column;align-items:center;cursor:pointer;
    padding:6px 4px 5px;box-sizing:border-box;transition:transform .1s}
  .m-tb-cell:active{transform:scale(0.96)}
  .m-tb-cell img{width:70%;height:50%;object-fit:contain;pointer-events:none;margin-top:1px}
  .m-tb-cell .m-pd-name{width:100%;text-align:center;font-family:'Cinzel',serif;font-weight:700;
    font-size:9px;letter-spacing:.01em;text-transform:uppercase;color:#e8dcc0;
    overflow:hidden;white-space:nowrap;text-overflow:ellipsis;margin-top:auto}
  .m-tb-cell .m-tb-act{display:block;width:100%;margin-top:4px;padding:2px 0;border-radius:5px;
    background:linear-gradient(180deg,#3a2c60,#241a40);border:1px solid #caa14e88;box-sizing:border-box;
    text-align:center;font-family:'Cinzel',serif;font-size:8px;font-weight:800;
    text-transform:uppercase;letter-spacing:.03em;color:#ffd98a}
  #m-econ-panel{position:fixed;inset:0;z-index:520;background:rgba(0,0,0,0.8);
    display:none;align-items:flex-end;justify-content:center}
  #m-econ-panel.open{display:flex}

  /* EVENT panel base overlay — sibling of #m-econ-panel, same stacking layer (520).
     Content-level rules (.m-event-inner, .m-event-titlebar, #m-event-body) live in lobby.html. */
  #m-event-panel{position:fixed;inset:0;z-index:520;background:rgba(0,0,0,0.8);
    display:none;align-items:center;justify-content:center;padding:16px}
  #m-event-panel.open{display:flex}

  /* ═══════ Gem Altar — weapon PASSIVE upgrade only, house frame.webp skin ═══════
     Own class family (not reusing lobby.html's inline .m-craft-* rules) so this popup has zero
     dependency on the rest of the lobby's chrome/CSS -- it needs to keep working unchanged once it's
     embedded standalone in the running 3D game. Sized like the Store (bigger than Settings: this one
     needs a weapon list AND a detail pane side by side, not a single centered column). The outer
     .m-galtar-land establishes the container-query root in vw/vh/px (unavoidable -- a container can't
     size itself in its own cqw/cqh); every element INSIDE it is cqw/cqh only, per the project's fixed
     landscape-mobile scale rule. */
  .m-galtar-land{container-type:size;position:relative;
    width:min(1100px,96vw,calc(88vh*1525/856));aspect-ratio:1525/856;
    max-width:none;max-height:none;height:auto;display:flex;flex-direction:column;padding:0;overflow:visible;
    background:url('heropopup/frame.webp') center/100% 100% no-repeat;
    border:none;border-radius:0;box-shadow:0 26px 80px #000d}
  .m-galtar-close{position:absolute;top:-2.4cqh;right:-1.6cqw;width:4.6cqw;height:auto;aspect-ratio:1;z-index:4;
    padding:0;border:none;border-radius:0;box-shadow:none;font-size:0;cursor:pointer;
    background:url('heropopup/close.webp') center/contain no-repeat}
  .m-galtar-close:hover{filter:brightness(1.12)}
  .m-galtar-title{flex:none;position:relative;z-index:2;text-align:center;font-family:'Cinzel',serif;
    font-weight:900;letter-spacing:.1em;text-transform:uppercase;font-size:3.1cqw;
    padding:5cqh 8cqw 0;color:#f0d78f;text-shadow:0 2px 4px #000d,0 0 1.2cqw #ffd98a33}
  .m-galtar-body{flex:1;min-height:0;display:flex;gap:1.6cqw;padding:3cqh 3.4cqw 3cqh;overflow:hidden}
  .m-galtar-collabel{flex:none;font-family:'Cinzel',serif;font-weight:800;letter-spacing:.08em;
    font-size:1.8cqw;color:#8a93ad;text-transform:uppercase;margin-bottom:.3cqh}
  /* Same divider the Forge uses under its own "Weapon" column label -- craft_separator.webp,
     same aspect-ratio, same treatment (see .m-craft-sep in lobby.html). */
  .m-galtar-sep{flex:none;width:100%;aspect-ratio:1313/100;
    background:url('heropopup/craft_separator.webp') center/100% 100% no-repeat;
    margin-bottom:.6cqh;opacity:.9}

  /* LEFT — the weapon list (only weapons with core.element; un-imbued weapons never show here) */
  .m-galtar-left{flex:0 0 32%;min-width:0;display:flex;flex-direction:column;min-height:0}
  .m-galtar-wlist{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;
    gap:.8cqh;padding-right:.2cqw}
  /* MATCHED TO THE FORGE'S ROW (2026-09-16). Roman: "in Passive, the weapon selection window on the
     left should be identical to the one in the Forge." The two had drifted — different padding (and
     on a different unit AXIS, .7cqh vs .72cqw), a different background, and no box-sizing here.

     ⚠ THE NUMBERS CANNOT SIMPLY BE COPIED and be the same SIZE, which is why this matches the
     STYLE and not the pixels. The two panels are different container-query roots: .m-econ-inner is
     min(1900px,99vw,97vh*2.2196), .m-galtar-land is min(1100px,96vw,88vh*1.7816). Both are
     height-bound on a landscape phone, so this container is a constant ~73% of the Forge's width and
     an identical cqw renders ~27% smaller here. Same design, sized for its own frame. */
  .m-galtar-wrow{position:relative;flex:none;display:flex;align-items:center;gap:.8cqw;width:100%;min-width:0;
    border:none;cursor:pointer;text-align:left;padding:.72cqw .9cqw;border-radius:.9cqw;box-sizing:border-box;
    background:rgba(15,10,32,.55);box-shadow:inset 0 0 0 1px #3a2c6055}
  .m-galtar-wrow.sel{box-shadow:inset 0 0 0 2px #ffd98a;background:rgba(60,45,15,.5)}
  /* The Forge's gem-socket, not a flat square — this was the loudest difference between the two
     lists. overflow:hidden stays (the Altar's icon can fall back to a NAME via _pdOnerrorImg, which
     is better than the Forge's visibility:hidden and is deliberately kept). */
  .m-galtar-wicon{flex:none;width:4cqw;aspect-ratio:1;border-radius:1cqw;
    background:radial-gradient(ellipse at 50% 35%,#26325a,#111a34);box-shadow:inset 0 0 0 1px #caa14e66;
    display:flex;align-items:center;justify-content:center;overflow:hidden}
  .m-galtar-wicon img{width:78%;height:78%;object-fit:contain;filter:drop-shadow(0 2px 3px #0009)}
  .m-galtar-wtext{flex:1;min-width:0}
  /* THE SELECTED-ROW CHECK, SHARED BY BOTH WEAPON LISTS (2026-09-16). Was .m-craft-wcheck, inline in
     lobby.html and Forge-only; promoted here rather than copied, the same call .m-eq-badge already
     made. Two byte-identical rules under two names is exactly how .m-craft-wrow and .m-galtar-wrow
     drifted apart in the first place.

     ⚠ The Forge's inline copy is DELETED in the same commit. popups.css is <link>ed before
     lobby.html's inline <style>, so an inline rule of equal specificity would silently win and the
     two would diverge again without anyone noticing. */
  /* THE BADGE GETS ITS OWN LINE IN BOTH LISTS. It began inline-after-the-name in the Altar and on
     its own line in the Forge, whose column is narrower — then the Altar adopted the Forge's
     padding and its inline pill started clipping too ("Equip..."). One flow for both: the name keeps
     its ellipsis line to itself, and the pill can never be truncated by it. */
  .m-craft-wtext .m-eq-badge,
  .m-galtar-wtext .m-eq-badge{display:inline-block;margin-left:0;margin-top:.35cqh}
  .m-wcheck{flex:none;width:2.5cqw;height:2.5cqw;border-radius:50%;background:#3cae5a;
    box-shadow:0 0 0 2px #143a1e;display:flex;align-items:center;justify-content:center}
  .m-wcheck::after{content:'';width:38%;height:60%;border-right:.32cqw solid #eafff0;border-bottom:.32cqw solid #eafff0;
    transform:rotate(40deg) translate(-8%,-12%)}
  .m-galtar-wname{font-family:'Cinzel',serif;font-weight:800;font-size:1.85cqw;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  /* The row for the weapon actually in the hero's hands — it leads the list and says so, because
     levelling the wrong weapon is invisible until a quest refuses to move (see gem-altar.js). */
  .m-galtar-wrow.eq{box-shadow:inset 0 0 0 1px #6ad39a77;background:rgba(18,38,28,.55)}
  .m-galtar-wrow.eq.sel{box-shadow:inset 0 0 0 2px #ffd98a;background:rgba(60,45,15,.5)}
  /* ONE badge for every list that marks the held weapon — the Gem Altar and the Forge both use it.
     Was .m-galtar-weq until 2026-09-16; renamed rather than copied into the Forge's own stylesheet,
     because two identical rules under two names is how .m-craft-wrow and .m-galtar-wrow already
     drifted. Lives here, in popups.css, which is loaded on the same page as the Forge. */
  .m-eq-badge{margin-left:.6cqw;padding:.1cqh .5cqw;border-radius:.5cqw;vertical-align:middle;
    font-family:system-ui,sans-serif;font-size:1.15cqw;font-weight:700;letter-spacing:.04em;
    color:#0d2419;background:#6ad39a}
  .m-galtar-eqwarn{flex:none;margin-bottom:.6cqh;padding:.7cqh .8cqw;border-radius:.9cqw;
    background:rgba(60,30,20,.55);box-shadow:inset 0 0 0 1px #d3866a55;
    color:#ffb99a;font-size:1.45cqw;line-height:1.45}
  .m-galtar-wlvl{font-size:1.55cqw;color:#ffd98a;font-weight:800;letter-spacing:.03em}
  .m-galtar-wlvl.off{color:#8a7ab0;font-weight:400}
  .m-galtar-welem{flex:none;width:2.4cqw;height:2.4cqw;object-fit:contain}
  .m-galtar-empty{color:#8a93ad;font-size:1.9cqw;padding:2cqw;text-align:center;line-height:1.6;margin:auto}

  /* RIGHT — the selected weapon's NOW / AFTER passive detail */
  .m-galtar-right{flex:1;min-width:0;min-height:0;display:flex;flex-direction:column;
    background:rgba(15,10,28,.4);border-radius:1cqw;box-shadow:inset 0 0 0 1px #3a2c6055;
    padding:1.6cqh 1.6cqw;overflow-y:auto}
  .m-galtar-dhead{flex:none;display:flex;align-items:center;gap:1cqw;margin-bottom:1.2cqh}
  .m-galtar-dgem{width:5cqw;height:5cqw;object-fit:contain;filter:drop-shadow(0 3px 8px rgba(0,0,0,.7))}
  .m-galtar-dname{font-family:'Cinzel',serif;font-weight:900;font-size:2.4cqw;color:#f0d78f;text-transform:uppercase}
  .m-galtar-dlvl{font-size:1.6cqw;color:#c0a0f0;font-weight:700}
  .m-galtar-stage{flex:none;border:1px solid #3a2860;border-radius:.9cqw;padding:1.1cqh 1.2cqw;margin-bottom:1.1cqh;
    background:linear-gradient(180deg,rgba(46,36,86,.5),rgba(30,24,62,.5))}
  .m-galtar-stage-lbl{font-family:'Cinzel',serif;font-weight:800;letter-spacing:.08em;font-size:1.45cqw;
    color:#8a93ad;text-transform:uppercase;margin-bottom:.3cqh}
  .m-galtar-stage-main{font-family:'Cinzel',serif;font-weight:800;font-size:2.05cqw;color:#fff;margin-bottom:.2cqh}
  .m-galtar-stage-main.dim{color:#8a7ab0;font-weight:600}
  .m-galtar-stage-sub{font-size:1.55cqw;color:#c0a0f0;line-height:1.4}
  .m-galtar-stage.next .m-galtar-stage-main{color:#7ee29a}
  .m-galtar-mastery{flex:none;font-size:1.45cqw;color:#ffd98a;font-style:italic;margin-bottom:.6cqh}
  /* Bottom action row -- same shape as the Forge's Imbue bar (.m-craft-bottombar/.m-craft-bb-item
     in lobby.html): a hairline divider, a couple of label/value stats, then the action button
     sharing the row (flex:1 on the button itself, set inline, exactly like .m-craft-imbue). */
  .m-galtar-bottombar{flex:none;display:flex;align-items:center;gap:1.2cqw;margin-top:auto;
    padding-top:1cqh;border-top:1px solid #3a2c6055}
  .m-galtar-bb-item{flex:none;display:flex;flex-direction:column;align-items:flex-start;gap:.15cqh}
  .m-galtar-bb-item .lbl{font-family:'Cinzel',serif;font-weight:800;letter-spacing:.05em;font-size:1.2cqw;
    color:#8a93ad;text-transform:uppercase}
  .m-galtar-bb-item .val{font-family:'Cinzel',serif;font-weight:900;font-size:1.7cqw;color:#f0e4c0;
    display:flex;align-items:center;gap:.3cqw}
  .m-galtar-bb-item .val.good{color:#7ee29a}
  .m-galtar-bb-item .val.poor{color:#ff8a75}
  /* The ad was watched for this level (2026-09-27) — the forge's own look, sized for this window. */
  .m-galtar-bb-item .val.boosted{color:#9dffb4;text-shadow:0 0 .6cqw #3dff7a88}
  .m-galtar-bottombar .m-craft-adboost{font-size:1.5cqw;padding:.5cqh .8cqw}
  .m-galtar-bottombar .m-craft-adboost img{width:2.4cqw}
  .m-galtar-bb-item .val img{width:1.4cqw;height:1.4cqw;object-fit:contain}
  .m-galtar-bb-item .val .have{font-size:.85em;color:#8a93ad;font-weight:700}
  /* BIGGER (Roman, 2026-09-27, at the altar: "make the Upgrade button bigger") — 16cqw from 11. */
  .m-galtar-actbtn{flex:none;position:relative;width:16cqw;aspect-ratio:723/202;margin-left:auto;
    border:none;padding:0;cursor:pointer;background:url('heropopup/golden_button.webp') center/100% 100% no-repeat;
    font-family:'Cinzel',serif;font-weight:900;letter-spacing:.06em;font-size:1.8cqw;color:#3a1c08;
    text-transform:uppercase;display:flex;align-items:center;justify-content:center}
  .m-galtar-actbtn:disabled{opacity:.45;cursor:default;filter:grayscale(.5)}
  .m-galtar-actbtn:not(:disabled):hover{filter:brightness(1.1)}

  /* ═══════ Quest popup v2 (PROTOTYPE) — tmp/six elements/task art ═══════
     Portrait card (607x909). Region boundaries below are MEASURED off frame.webp (PowerShell
     pixel-sampled the vertical center + two horizontal rows, not eyeballed): wood banner ends /
     navy body starts at y=120px (13.2cqh), body ends / footer divider starts at y=768 (84.5cqh),
     footer strip runs 87.8-97.7cqh, and the navy area's usable left/right inner edge is ~4.5% in
     on both the body row (y=400) and the footer row (y=840). Keep everything inside those bands.
     cqw and cqh are a FIXED ratio here (909/607) since .m-quest2-land is aspect-ratio-locked, so
     the row-list math below mixes both freely without them ever drifting apart. */
  /* NOT background:none here -- #quest2-modal .m-look-modal (id+class) out-specifies the plain
     .m-quest2-land{background:url(frame.webp)} (class-only) below, so it was silently winning and
     blanking the frame out entirely. Only strip the base .m-look-modal chrome that .m-quest2-land
     doesn't already redeclare itself (border/padding/shadow) -- leave background alone. */
  #quest2-modal .m-look-modal{border:none;border-radius:0;padding:0;box-shadow:none;overflow:visible}
  /* Shared .m-look-overlay (hero-port.css) sets 16px -- scoped down here so every OTHER popup on
     that same class keeps its normal margin; only quest2 wants to run edge-to-edge. */
  #quest2-modal{padding:2px}
  .m-quest2-land{container-type:size;position:relative;
    height:min(900px,98vh,calc(54vw*909/607));aspect-ratio:607/750;
    max-width:none;max-height:none;width:auto;display:block;padding:0;overflow:visible;
    background:url('heropopup/quest2/frame.webp') center/100% 100% no-repeat}
  .m-quest2-close{position:absolute;top:-0.2cqh;right:-2.6cqh;width:8.4cqh;height:auto;aspect-ratio:1;z-index:4;
    padding:0;border:none;border-radius:0;box-shadow:none;font-size:0;cursor:pointer;
    background:url('heropopup/close.webp') center/contain no-repeat}
  .m-quest2-close:hover{filter:brightness(1.12)}
  .m-quest2-title{position:absolute;left:16%;right:16%;top:2.5cqh;height:10.2cqh;z-index:2;
    display:flex;align-items:center;justify-content:center;text-align:center;
    font-family:'Cinzel',serif;font-weight:900;letter-spacing:.06em;font-size:4.3cqh;color:#fff;
    text-shadow:0 1px 3px rgba(0,0,0,.8)}
  /* body band: 13.2cqh-84.5cqh measured; inset slightly so rows never touch the border. Scrollbar
     hidden entirely (not just thinned) -- a touch UI reads "content keeps going" from the row just
     getting cut off at the edge, a visible scrollbar was just extra chrome. */
  .m-quest2-body{position:absolute;left:5.6%;right:6.6%;top:14cqh;bottom:16cqh;z-index:2;
    overflow-y:auto;overflow-x:hidden;scrollbar-width:none}
  .m-quest2-body::-webkit-scrollbar{display:none}
  .m-quest2-empty{text-align:center;color:#8fa0c0;font-family:'Cinzel',serif;font-size:4cqh;padding:4cqh 1cqw}
  /* Two columns: a fixed-width node/line timeline on the left, task bars filling the rest.
     Node-slot height is HARDCODED (not aspect-ratio) to exactly match the row's own
     aspect-ratio-derived height at ITS width (78cqw here) -- aspect-ratio on the slim node
     column would give a totally different (much shorter) height than the wide row column, so
     matching them requires one to give up aspect-ratio and just state the number. */
  .m-quest2-list{display:flex;gap:3cqw}
  .m-quest2-nodecol{flex:none;width:10cqw;position:relative}
  .m-quest2-lineglow{position:absolute;left:50%;top:9%;width:.6cqw;transform:translateX(-50%);
    background:linear-gradient(180deg,#c8ffb0,#5ad02a);border-radius:1cqh;
    box-shadow:0 0 1.4cqw rgba(140,255,90,.9);z-index:0}
  .m-quest2-linedim{position:absolute;left:50%;top:9%;bottom:9%;width:.5cqw;transform:translateX(-50%);
    background:rgba(255,255,255,.14);border-radius:1cqh;z-index:-1}
  .m-quest2-nodeslot{position:relative;height:19.43cqw;margin-bottom:1cqw;display:flex;align-items:center;justify-content:center}
  /* Text color is white everywhere in this popup regardless of row/node state (was dark-brown on
     gold/green, light-gray on locked -- inconsistent, and the user's flagged standing rule is one
     text color per popup, not one-per-background). Shadow strength is what carries contrast now. */
  .m-quest2-node{position:relative;z-index:1;width:66%;aspect-ratio:1;border-radius:50%;
    display:flex;align-items:center;justify-content:center;
    font-family:'Cinzel',serif;font-weight:900;font-size:3.6cqh;color:#fff;text-shadow:0 1px 3px rgba(0,0,0,.85);
    background:radial-gradient(ellipse at 50% 32%,#eafff0,#3ba848);
    box-shadow:0 0 .9cqw rgba(140,255,90,.75),inset 0 0 0 .15cqh rgba(0,0,0,.3)}
  .m-quest2-node.current{background:radial-gradient(ellipse at 50% 32%,#fff3c0,#e0a020);
    box-shadow:0 0 1.2cqw rgba(255,210,90,.95),inset 0 0 0 .15cqh rgba(0,0,0,.3)}
  .m-quest2-node.locked{background:radial-gradient(ellipse at 50% 32%,#9aa7b6,#4c5560);
    box-shadow:inset 0 0 0 .15cqh rgba(0,0,0,.3)}
  .m-quest2-node img{width:58%;height:58%;object-fit:contain}
  .m-quest2-rowcol{flex:1;min-width:0}
  .m-quest2-row{position:relative;width:100%;height:19.43cqw;margin-bottom:1cqw;
    background:center/100% 100% no-repeat;display:flex;align-items:center;padding:0 4%}
  .m-quest2-row.done{background-image:url('heropopup/quest2/task_done.webp')}
  .m-quest2-row.current{background-image:url('heropopup/quest2/current_task.webp')}
  .m-quest2-row.locked{background-image:url('heropopup/quest2/task_not_ready.webp')}
  /* Icon (left) / text+progress stacked (middle) / reward (right, absolute -- see .m-quest2-rw)
     -- matches the reference: a picture identifying the task, not just a number. */
  .m-quest2-icon{flex:none;width:16%;aspect-ratio:1;margin-right:2.5%;display:flex;
    align-items:center;justify-content:center;font-size:3.4cqh;line-height:1;
    filter:drop-shadow(0 2px 3px rgba(0,0,0,.55))}
  /* Monster portrait in place of the emoji. contain, not cover: the art runs 155x159 to
     400x398 and cropping a square out of a wide salamander cuts its head off. */
  .m-quest2-mon{width:100%;height:100%;object-fit:contain}
  .m-quest2-mid{flex:1;min-width:0;display:flex;flex-direction:column;gap:.5cqh;padding-right:19%}
  .m-quest2-lbl{font-family:'Cinzel',serif;font-weight:800;font-size:3.9cqw;color:#fff;
    white-space:normal;line-height:1.15;text-shadow:0 1px 3px rgba(0,0,0,.85)}
  .m-quest2-bar{position:relative;width:78%;height:3.2cqw;border-radius:1cqh;background:rgba(0,0,0,.32);
    box-shadow:inset 0 0 0 1px rgba(0,0,0,.25);overflow:hidden}
  .m-quest2-barfill{position:absolute;inset:0 auto 0 0;background:linear-gradient(180deg,#ffdb7a,#e8971f);border-radius:1cqh}
  .m-quest2-barlbl{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
    font-size:2.6cqw;font-weight:800;color:#fff;text-shadow:0 1px 1px rgba(0,0,0,.7)}
  /* Single reward (gold/crystal/chest): column, icon THEN number (see _quest2RewardHtml -- the
     img now comes before the span in the markup), so the count always sits under the image, never
     beside it. */
  .m-quest2-rw{position:absolute;right:3.6%;top:50%;transform:translateY(-50%);width:16%;aspect-ratio:1;
    display:flex;align-items:center;justify-content:center;flex-direction:column;flex-wrap:nowrap;gap:.2cqw}
  .m-quest2-rw .m-quest2-rwicon{width:68%;height:68%;object-fit:contain;filter:drop-shadow(0 1px 2px rgba(0,0,0,.5))}
  /* Multiple reward icons (the "element" quest -- a random gem, shown as a few sample gem icons)
     side by side instead of stacked, and shrunk so 3 of them actually fit the slot. */
  .m-quest2-rw.multi{flex-direction:row}
  .m-quest2-rw.multi .m-quest2-rwicon{width:30%;height:30%}
  .m-quest2-rw .m-quest2-rwtxt{font-family:'Cinzel',serif;font-weight:900;font-size:3.2cqw;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.7)}
  /* footer band: 87.8-97.7cqh measured, same 4.5% left/right inner edge as the body */
  .m-quest2-navbar{position:absolute;left:4.6%;right:4.6%;top:87.3cqh;bottom:2.2cqh;z-index:2;
    display:flex;align-items:center;justify-content:space-between;gap:2%}
  .m-quest2-navbtn{flex:1;position:relative;height:82%;border:none;padding:0;cursor:pointer;
    background:url('heropopup/quest2/button_nav.webp') center/100% 100% no-repeat;
    font-family:'Cinzel',serif;font-weight:800;letter-spacing:.04em;font-size:3.8cqh;color:#c8d6ea;
    text-shadow:0 1px 2px rgba(0,0,0,.6)}
  .m-quest2-navbtn.active{background-image:url('heropopup/quest2/button_nav_selected.webp');color:#3a2408;
    text-shadow:0 1px 1px rgba(255,220,150,.5)}
  .m-quest2-navbtn:active{transform:scale(.96)}

  /* ═══════ Daily/Weekly tab — daily_timer.webp + progress_empty.webp ═══════
     Text-slot / track bounds below are PowerShell pixel-sampled off each PNG (same method as the
     main frame), not eyeballed. */
  .m-quest2-timer{position:relative;width:92%;aspect-ratio:1030/228;margin:0 auto 1.6cqw;
    background:url('heropopup/quest2/daily_timer.webp') center/100% 100% no-repeat}
  /* dark text-slot measured at x=330-735 of 923 (35.7%-79.6%) */
  .m-quest2-timertext{position:absolute;left:36%;right:20.5%;top:0;bottom:0;
    display:flex;align-items:center;justify-content:center;
    font-family:'Cinzel',serif;font-weight:900;font-size:4.2cqw;color:#fff;
    text-shadow:0 1px 3px rgba(0,0,0,.85);letter-spacing:.04em}
  .m-quest2-progresswrap{position:relative;width:98%;aspect-ratio:1186/177;margin:0 auto 2.2cqw;
    background:url('heropopup/quest2/progress_empty.webp') center/100% 100% no-repeat}
  /* transparent track measured at x=206-1086 (17.4%-91.6%), y=89-129 of 177 (50.3%-72.9%) */
  .m-quest2-progresstrack{position:absolute;left:17.4%;right:8.4%;top:50.3%;bottom:27.1%;
    border-radius:1cqh;background:rgba(30,18,10,.6);box-shadow:inset 0 0 0 1px rgba(0,0,0,.3);overflow:hidden}
  .m-quest2-progressfill{position:absolute;inset:0 auto 0 0;border-radius:1cqh;
    background:linear-gradient(180deg,#fff3b0,#ffb020);box-shadow:0 0 .8cqw rgba(255,200,80,.85)}
  .m-quest2-progresstext{position:absolute;left:17.7%;right:8.9%;top:8px;bottom:0;z-index:2;
    display:flex;align-items:center;justify-content:center;
    font-family:'Cinzel',serif;font-weight:900;font-size:3.7cqw;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.8)}
  /* Flat row list -- same task-row art as Main, no node/line column (daily/weekly have no fixed
     unlock sequence to show), plain stacked block children instead of the two-column flex list. */
  .m-quest2-flatlist{display:flex;flex-direction:column}


  /* (dev) quest skip — deliberately plain and ugly so it never reads as shipped UI. */
  .m-quest2-devskip{display:block;width:100%;margin-top:1.2cqh;padding:1cqh 0;font-family:monospace;
    font-size:3cqw;letter-spacing:.5px;color:#ffd9a0;background:#3a2a12;border:1px dashed #b98a3a;
    border-radius:.6cqh;cursor:pointer}
  .m-quest2-devskip:disabled{opacity:.6;cursor:default}

  /* ═══════ THE DAILY BAR'S PRIZE (2026-09-24) — the helmet became a crystal ═══════
     progress_crystal.webp is progress_empty.webp with a crystal medallion (same 1186x177, same track
     bounds), and the amount is HTML so it is always the server's number (dailyBonusCrystals). */
  .m-quest2-progresswrap.crystal{background-image:url('heropopup/quest2/progress_crystal.webp')}
  .m-quest2-bonus{position:absolute;left:4.2%;width:13.5%;bottom:4%;z-index:3;text-align:center;
    font-family:'Cinzel',serif;font-weight:900;font-size:3.2cqw;color:#fff;
    text-shadow:0 0 .4cqw #000,0 1px 2px #000,0 0 1cqw rgba(80,170,255,.8)}
  .m-quest2-bonus.paid{color:#9dffa0}

  /* ═══════ THE QUEST LOG'S ARENA TAB (2026-09-24) — the helmet IS Arena points ═══════ */
  .m-quest2-progresswrap.arena .m-quest2-arenatext{position:absolute;left:17.7%;right:8.9%;top:44%;bottom:22%;z-index:2;
    display:flex;align-items:center;justify-content:center;gap:2cqw;
    font-family:'Cinzel',serif;font-weight:900;font-size:3.6cqw;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.85)}
  .m-quest2-arenatext .place{color:#ffd66e}
  .m-quest2-sechead{font-family:'Cinzel',serif;font-weight:900;font-size:3.4cqw;color:#f0d78f;
    letter-spacing:.05em;text-transform:uppercase;margin:1.4cqh 0 .6cqh 1cqw;text-shadow:0 1px 2px #000a}
  .m-quest2-locked{padding:6cqh 4cqw;text-align:center;font-family:'Cinzel',serif;font-weight:800;
    font-size:3.8cqw;line-height:1.5;color:#e8dcc0;text-shadow:0 1px 2px #000a}
  .m-quest2-rw .m-quest2-rwtxt.tier{font-size:2.8cqw}

  /* ═══════ THE ARENA WINDOW (2026-09-24) ═══════
     Leaf-corner frame (heropopup/stash/big_frame.webp, 1125x680) — a placeholder for Roman's own art,
     so the structure is three plain columns that a reskin can restyle without touching arena.js. */
  .m-arena-land{container-type:size;position:relative;
    width:min(900px,98vw,calc(92vh*1125/680));aspect-ratio:1125/680;
    max-width:none;max-height:none;height:auto;padding:0;overflow:visible;
    background:url('heropopup/stash/big_frame.webp') center/100% 100% no-repeat;
    border:none;border-radius:0;box-shadow:0 26px 80px #000d;color:#fff}
  .m-arena-close{position:absolute;top:1.4cqw;right:1.4cqw;width:9.8cqh;height:auto;aspect-ratio:1;
    z-index:4;padding:0;border:none;font-size:0;cursor:pointer;color:transparent;
    background:url('heropopup/close.webp') center/contain no-repeat}
  .m-arena-title{position:absolute;top:7cqh;left:0;right:0;text-align:center;
    font-family:'Cinzel',serif;font-weight:900;letter-spacing:.08em;font-size:3.6cqw;color:#f0d78f;
    text-shadow:0 2px 4px #000b,0 0 1.2cqw #ffd98a44}
  .m-arena-cols{position:absolute;left:4.5cqw;right:4.5cqw;top:16cqh;bottom:6cqh;
    display:grid;grid-template-columns:26% 33% 1fr;gap:2cqw}
  .m-arena-left{position:relative;min-height:0}
  .m-arena-hero{position:absolute;inset:0}
  .m-arena-hero .m-char-preview{position:absolute;inset:0}
  .m-arena-hero img.m-prev-layer{position:absolute;inset:0;width:100%;height:100%;object-fit:contain}
  .m-arena-mid{display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:1.6cqh;min-height:0}
  .m-arena-score{display:flex;align-items:center;gap:1.4cqw;margin-top:1cqh}
  .m-arena-helmet{width:9cqw;height:auto}
  .m-arena-pts{font-family:'Cinzel',serif;font-weight:900;font-size:4.2cqw;line-height:1.05;text-shadow:0 2px 3px #000c}
  .m-arena-ptslbl{font-size:1.9cqw;color:#e8dcc0}
  .m-arena-place{font-family:'Cinzel',serif;font-weight:900;font-size:3cqw;color:#ffd66e;text-shadow:0 1px 2px #000c}
  .m-arena-place.none{font-size:1.8cqw;color:#c7bfe0}
  .m-arena-enter{width:92%;aspect-ratio:723/202;border:none;padding:0;cursor:pointer;
    background:url('heropopup/golden_button.webp') center/100% 100% no-repeat;
    font-family:'Cinzel',serif;font-weight:900;letter-spacing:.06em;font-size:2.4cqw;color:#3a1c08;
    display:flex;align-items:center;justify-content:center}
  .m-arena-enter:hover{filter:brightness(1.1)}
  .m-arena-enter:active{transform:scale(.97)}
  .m-arena-how{width:100%;display:flex;flex-direction:column;gap:.6cqh}
  .m-arena-howrow{display:flex;align-items:center;gap:1cqw;padding:.5cqh 1cqw;border-radius:.8cqw;background:rgba(10,20,40,.45)}
  .m-arena-howrow img{width:3.6cqw;height:3.6cqw;object-fit:contain;flex:none}
  .m-arena-howrow .lbl{flex:1;font-size:1.65cqw;color:#e8dcc0;line-height:1.2}
  .m-arena-howrow .val{font-family:'Cinzel',serif;font-weight:900;font-size:1.9cqw;color:#ffd66e}
  .m-arena-reset{font-size:1.6cqw;color:#c7bfe0;text-align:center}
  .m-arena-right{display:flex;flex-direction:column;min-height:0}
  .m-arena-walltitle{font-family:'Cinzel',serif;font-weight:900;font-size:2.4cqw;color:#f0d78f;text-align:center;letter-spacing:.05em;text-shadow:0 1px 2px #000b}
  .m-arena-champs{display:flex;justify-content:center;gap:1.2cqw;margin:.6cqh 0 .8cqh;font-size:1.35cqw;color:#e8dcc0;flex-wrap:wrap}
  .m-arena-champs .lbl{width:100%;text-align:center;color:#c7bfe0;font-size:1.3cqw}
  .m-arena-champs .c{white-space:nowrap}
  .m-arena-wall{flex:1;min-height:0;overflow-y:auto;border-radius:1cqw;background:rgba(5,12,28,.55);padding:.6cqh .6cqw}
  .m-arena-wrow{display:grid;grid-template-columns:4.2cqw 1fr 5.2cqw 7.4cqw;align-items:center;gap:.6cqw;
    padding:.55cqh .6cqw;border-bottom:1px solid rgba(255,255,255,.06);font-size:1.6cqw}
  .m-arena-wrow.you{background:rgba(255,214,110,.16);border-radius:.6cqw}
  .m-arena-wrow .pl{font-family:'Cinzel',serif;font-weight:900;text-align:center}
  .m-arena-wrow .nm{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .m-arena-wrow .lv{color:#c7bfe0;font-size:1.35cqw}
  .m-arena-wrow .pt{display:flex;align-items:center;justify-content:flex-end;gap:.4cqw;font-weight:800}
  .m-arena-wrow .pt img{width:2cqw;height:2cqw}
  .m-arena-youpin{margin-top:.6cqh}
  .m-arena-wallmsg{padding:3cqh 1cqw;text-align:center;font-size:1.7cqw;color:#c7bfe0}

  /* ═══════ LAST WEEK'S PRIZE ═══════ */
  .m-arena-prize-land{container-type:size;position:relative;
    width:min(720px,96vw,calc(86vh*1125/680));aspect-ratio:1125/680;
    max-width:none;max-height:none;height:auto;padding:0;overflow:visible;
    background:url('heropopup/stash/big_frame.webp') center/100% 100% no-repeat;
    border:none;border-radius:0;box-shadow:0 26px 80px #000d;color:#fff}
  .m-arena-prize-title{position:absolute;top:10cqh;left:6cqw;right:6cqw;text-align:center;
    font-family:'Cinzel',serif;font-weight:900;font-size:3.4cqw;color:#f0d78f;text-shadow:0 2px 4px #000b}
  .m-arena-prize-body{position:absolute;left:6cqw;right:6cqw;top:21cqh;bottom:8cqh;
    display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2.4cqh}
  .m-arena-prize-sub{font-size:2.6cqw;color:#e8dcc0;text-align:center}
  .m-arena-prize-big{display:flex;align-items:center;gap:1.4cqw;font-family:'Cinzel',serif;font-weight:900;font-size:5cqw}
  .m-arena-prize-big img{width:9cqw;height:auto}
  .m-arena-prize-btn{width:34%;aspect-ratio:723/202;border:none;padding:0;cursor:pointer;
    background:url('heropopup/golden_button.webp') center/100% 100% no-repeat;
    font-family:'Cinzel',serif;font-weight:900;letter-spacing:.06em;font-size:2.6cqw;color:#3a1c08}
  .m-arena-prize-btn:disabled{opacity:.55;cursor:default}
  .m-arena-cards{display:grid;grid-template-columns:repeat(3,1fr);gap:1.6cqw;width:100%}
  .m-arena-card{display:flex;flex-direction:column;align-items:center;gap:.8cqh;padding:1.4cqh 1cqw;
    border-radius:1.2cqw;border:2px solid var(--rc,#fff);background:rgba(5,12,28,.7);min-height:0}
  .m-arena-card img.ic{width:10cqw;height:10cqw;object-fit:contain}
  .m-arena-card .nm{font-family:'Cinzel',serif;font-weight:900;font-size:1.9cqw;color:var(--rc,#fff);text-align:center}
  .m-arena-card .lv{font-size:1.5cqw;color:#c7bfe0}
  .m-arena-card .st{font-size:1.45cqw;color:#e8dcc0;text-align:center;line-height:1.35}
  .m-arena-card .req{font-size:1.4cqw;color:#ffb070}
  .m-arena-card button{width:80%;aspect-ratio:723/202;border:none;padding:0;cursor:pointer;
    background:url('heropopup/golden_button.webp') center/100% 100% no-repeat;
    font-family:'Cinzel',serif;font-weight:900;font-size:1.9cqw;color:#3a1c08}

  /* A DAILY'S NAME, small under its objective (2026-09-24). The objective is the line now, and it runs
     longer than the old flavour title, so the daily list sets it a step smaller than a story step. */
  .m-quest2-flatlist .m-quest2-lbl{font-size:3.3cqw}
  .m-quest2-sub{font-family:'Cinzel',serif;font-weight:700;font-size:2.4cqw;color:#e8dcc0;
    line-height:1.1;margin-top:-.3cqh;text-shadow:0 1px 2px rgba(0,0,0,.85)}
