/* Portrait composition. All measurements follow the game surface, not viewport
   media queries: a desktop and a phone receive the same 9:16 layout. */
html body {display:grid;place-items:center;overflow:hidden;font-family:Nunito,'Segoe UI',sans-serif}
body #app {width:min(100vw,56.25dvh);height:min(100dvh,177.7778vw);max-height:none;flex:none;container-type:inline-size;overflow:hidden;background:linear-gradient(#301344b0,#37115c40 38%,#241038b8);border-inline:1px solid #8d55972b}
body #app::after{box-shadow:inset 0 0 8cqw #220c3440}
#app .hud,body:not(:has(#mapScreen:not([hidden]))) #app .hud {position:absolute;inset:0 0 auto;display:grid;grid-template-columns:9cqw 1fr 9cqw;gap:2.5cqw;width:100%;height:8%;padding:2.7cqw 3.7cqw;background:transparent}
#app .hud-title{display:none!important}
#app .hud #homeBtn{display:none}
#app:has(#gameScreen:not([hidden])) .hud #homeBtn{display:grid}
#app:has(#gameScreen:not([hidden])) .hud #settingsBtn{display:none}
#app .hud .square-button,#app #settingsBtn {width:9cqw;height:9cqw;min-height:0;padding:1cqw;border:0.3cqw solid #9551d7;border-radius:2.6cqw;background:linear-gradient(135deg,#7035ad,#48216d);box-shadow:inset 0 .4cqw .5cqw #dcb9ff5e,inset 0 -.7cqw 1cqw #27074780,0 .6cqw 1cqw #16032280}
#app #settingsBtn img {transform:none;width:100%;height:100%;object-fit:contain}
#app .wallets {display:grid;grid-template-columns:1fr 1.08fr 1.14fr;width:100%;gap:2cqw}
#app .wallet {display:flex;min-width:0;height:7.5cqw;min-height:0;padding:.4cqw 1cqw;gap:.3cqw;border:.25cqw solid #673183;border-radius:2.8cqw;background:linear-gradient(#301145,#271037);box-shadow:inset 0 .4cqw .5cqw #af6fc723,0 .4cqw .7cqw #1b052744}
#app .wallet img{width:5.7cqw;height:5.7cqw;flex:0 0 5.7cqw;margin:0}
#app .wallet b{font:900 3.2cqw Nunito,sans-serif;overflow:visible;text-overflow:clip;text-shadow:0 .25cqw .3cqw #120421}
#app .wallet small{display:block;font-size:2cqw;color:#bba7e9;margin:0}
#app .gem-wallet,#app .coin-wallet{display:flex;padding-right:4.9cqw}
#app .wallet-plus{width:4.1cqw;height:4.5cqw;right:.7cqw;border:.2cqw solid #ffe99a;border-radius:1.1cqw;font:900 3.5cqw Nunito;background:linear-gradient(#ffe680,#ffb53c);box-shadow:inset 0 .4cqw .4cqw #fff7c0,0 .4cqw 0 #844820}
#app .mail-button .notify-dot{width:2.6cqw;height:2.6cqw;top:-1cqw;right:-.7cqw}

#app #mapScreen {position:absolute;inset:8% 0 14%;width:100%;height:auto;min-height:0;max-height:none;margin:0;padding:0;display:block;transform:none!important;animation:none!important}
#app #mapScreen[hidden]{display:none}
#app .chapter-tabs{position:absolute;top:0;left:3.5%;width:93%;height:11%;gap:2cqw;padding:1.2cqw .5cqw 1.2cqw;mask-image:none}
#app .chapter-tab{flex:0 0 calc((100% - 6cqw)/4);min-width:0;height:100%;padding:1cqw .5cqw;gap:1cqw;border:.25cqw solid #703892;border-radius:3cqw;font-family:Nunito,sans-serif}
#app .chapter-tab span{display:block;font:900 2.8cqw Nunito;line-height:1.05;margin:0}
#app .chapter-tab small{font:600 2cqw Nunito;line-height:1.12;white-space:normal}
#app .chapter-tab.locked{filter:none;opacity:1;background:linear-gradient(#512375,#392052);color:#d8c9f1}
#app .chapter-tab .sprite-lock{width:3.6cqw;height:3.6cqw;top:-1.1cqw}
#app .chapter-tab[aria-pressed=true]{background:linear-gradient(135deg,#ffeb83,#ffd259 58%,#ffb744);box-shadow:inset 0 0 0 .6cqw #fff0ad,inset 0 1cqw 1cqw #fffac4,0 .55cqw 0 #c67423,0 0 3cqw #ffd45766;border:.3cqw solid #ffdf7b}
#app .chapter-pagination{position:absolute;top:11.4%;height:3%;gap:2.5cqw}
#app .chapter-pagination i{width:1.8cqw;height:1.8cqw}
#app .adventure-card{position:absolute;top:17%;left:12%;width:76%;height:66%;min-height:0;margin:0;padding:0;border:.75cqw solid #b878f7;border-radius:12cqw 12cqw 8cqw 8cqw;background:linear-gradient(#3a195bee,#26123de3);box-shadow:inset 0 .65cqw .3cqw #ebcbff, inset 0 0 0 .9cqw #743aa2,inset 0 0 3cqw #8033b066,0 0 0 .8cqw #56267a,0 1.3cqw 2cqw #14051e}
#app .adventure-card{border:0;border-radius:0;background:url(assets/ui/level-frame.svg) center/100% 100% no-repeat;box-shadow:none;display:block;text-align:center}
#app .adventure-card::before,#app .adventure-card::after{display:none}
#app .card-sparkle-top{top:-3.6cqw;left:calc(50% - 3.5cqw);width:7cqw;height:7cqw}
#app .card-sparkle-bottom{bottom:-3cqw;left:calc(50% - 2.6cqw);width:5.2cqw;height:5.2cqw}
#app .level-title-frame{position:absolute;top:1.5%;left:22%;width:56%;height:10%;margin:0;padding:0;display:grid;place-items:center;border:.5cqw solid #a964d5;border-radius:5cqw;background:linear-gradient(#512370,#301040);box-shadow:inset 0 .4cqw .5cqw #d29bed66,0 .5cqw 0 #4c1c66}
#app .level-title-frame h2{font:900 5.1cqw Nunito,sans-serif;line-height:1;margin:0;color:#fff2cc;text-shadow:0 .3cqw 0 #54243d}
#app .adventure-card .logo-subtitle{position:absolute;top:13%;width:100%;margin:0;font:800 3.1cqw Nunito;letter-spacing:0;text-transform:none}
#app .adventure-card .logo-subtitle::after{content:'◆';display:block;width:62%;height:2.6cqw;margin:1cqw auto 0;background:linear-gradient(90deg,transparent,#a17ab0 10% 42%,transparent 42% 58%,#a17ab0 58% 90%,transparent) center/100% .15cqw no-repeat;color:#ffda62;font-size:3cqw;line-height:2.6cqw}
#app .mini-scene{position:absolute;top:23%;left:0;width:100%;height:40%;margin:0;overflow:visible}
#app .mini-scene .level-hero-art{position:absolute;inset:-23% -15%;width:130%;height:145%;max-width:none;object-fit:contain;mask-image:radial-gradient(ellipse 80% 76% at center,#000 65%,transparent 100%);filter:saturate(.95) drop-shadow(0 .6cqw .8cqw #150922)}
#app .adventure-card>p{position:absolute;top:63%;left:4%;width:92%;max-width:none;height:7%;min-height:0;margin:0;padding:.8cqw 1cqw;display:grid;place-items:center;font:800 2.4cqw Nunito;line-height:1.1;background:linear-gradient(#3c1956,#28103f);border:.25cqw solid #754698;border-radius:3.5cqw 3.5cqw 0 0}
#app .goal-panel{position:absolute;top:70%;left:10%;width:80%;height:14%;padding:.7cqw 1.2cqw;border:.3cqw solid #72459a;border-radius:3cqw;background:#351b4cd9;box-shadow:inset 0 0 2cqw #70418333}
#app .goal-heading{font:800 2.3cqw Nunito;line-height:1.1;margin:0 0 .6cqw;gap:1cqw}
#app .goal-heading i{width:6cqw}
#app .preview-goals{height:66%;gap:1cqw}
#app .preview-goal{flex:1;min-width:0;width:auto;height:100%;gap:1cqw;padding:.2cqw .8cqw;border:.25cqw solid #694184;border-radius:2cqw;background:#27123d}
#app .preview-goal img{width:5cqw;height:5cqw;flex-shrink:0}
#app .preview-goal b{font:800 2.6cqw Nunito}
#app .adventure-card .play-button{position:absolute;bottom:2%;left:12%;width:76%;height:12%;min-height:0;margin:0;padding:0 3cqw;display:flex;align-items:center;justify-content:center;gap:3cqw;white-space:nowrap;border:.5cqw solid #fff0a1;border-radius:8cqw;font:1000 5.5cqw Nunito;letter-spacing:0;background:linear-gradient(165deg,#ffe77a,#ffd15c 60%,#ffb33c);box-shadow:inset 0 .7cqw .5cqw #fffbd1,inset 0 -.9cqw 0 #f59e34,0 .7cqw 0 #aa551d,0 0 0 .5cqw #fcca57;color:#591c12}
#app .adventure-card .play-button span{margin:0;font-size:4.5cqw}
#app #playBtn{animation:none;isolation:isolate;height:13%;bottom:2.5%}
#app #playBtn::before{content:'';position:absolute;inset:1.2cqw;border:.25cqw solid #fff3aa99;border-radius:inherit;pointer-events:none;z-index:-1;background:linear-gradient(155deg,#fff7b84d,transparent 50%)}
#app #playBtn::after{content:'';position:absolute;top:1.5cqw;left:3cqw;width:5cqw;height:1.8cqw;transform:rotate(-28deg);border-radius:50%;background:#fffbd3;pointer-events:none}
#app .card-leaves{bottom:4%;width:16cqw;height:20cqw;filter:drop-shadow(0 .5cqw .6cqw #10001a)}
#app .card-leaves-left{left:-5cqw;transform:rotate(-17deg)}
#app .card-leaves-right{right:-5cqw;transform:rotate(17deg)}
#app .atlas{position:absolute;top:87%;left:3%;width:94%;height:12%;padding:0}
#app .atlas-heading{display:none}
#app .level-carousel{grid-template-columns:9cqw 1fr 9cqw;gap:1cqw;height:100%}
#app .carousel-arrow{width:8.5cqw;height:8.5cqw;padding:1.5cqw}
#app .level-grid{height:100%;gap:1.5cqw;padding:1.2cqw .7cqw}
#app .level-cell{flex:0 0 calc((100% - 6cqw)/5);height:90%;min-width:0;padding:.4cqw;border:.3cqw solid #9555c8;border-radius:2.6cqw;font-family:Nunito;background:linear-gradient(#602e87,#3b1d5a);box-shadow:inset 0 .4cqw .5cqw #c18fe533,inset 0 -.5cqw 1cqw #220c3933}
#app .level-cell.current{height:100%;background:linear-gradient(#ffda69,#eebd50);border:.4cqw solid #fff4a4;box-shadow:inset 0 0 1.2cqw #fff9bf,0 0 2cqw #ffcc5888}
#app .level-cell>span{font:900 3.7cqw Nunito}
#app .level-cell small{font-size:2.6cqw;line-height:1;height:auto;margin:0}
#app .level-cell .dim-star{color:#9e702b}
#app .level-cell.locked{opacity:1;filter:none;color:#cfc1ef}
#app .level-cell.locked>span{opacity:1}
#app .level-cell.locked .sprite-lock{width:3.8cqw;height:3.8cqw;margin:0}
#app .level-cell::before,#app .level-cell::after{display:none}

#app #mainNav{position:absolute;left:3.7%;right:3.7%;bottom:3%;width:auto;height:10%;gap:2.2cqw;margin:0;padding:0;overflow:visible}
#app #mainNav .map-action{height:100%;padding:0;min-height:0;position:relative;border:.3cqw solid #9a55cb;border-radius:4cqw;background:linear-gradient(#5a2c7e,#321746);box-shadow:inset 0 .6cqw .6cqw #bd77e544,inset 0 -.7cqw 1cqw #1d0a303b}
#app #mainNav .map-action>img{position:absolute;left:5%;top:-27%;width:90%;height:105%;object-fit:contain;mask-image:none}
#app #mainNav .map-action>span{position:absolute;bottom:-.2cqw;left:-.3cqw;right:-.3cqw;height:38%;display:grid;place-items:center;border:.3cqw solid #72449c;border-radius:3cqw;background:linear-gradient(#4b2469,#351748);font:900 3cqw Nunito;line-height:1;color:#fff2d3;text-shadow:0 .3cqw .2cqw #1e0d2b}
#app #mainNav .map-action.active{border-color:#fff09e;box-shadow:inset 0 0 1cqw #ffdc80,0 0 2cqw #ffc74d,0 0 .6cqw #fff6b6}
#app #mainNav .map-action.active>span{border-color:#ffd773;color:#fff2b4}

/* Secondary pages retain a visible bottom bar and scroll only their contents. */
#app .section-screen,#app #bookScreen,#app #boardScreen{position:absolute;inset:8% 0 15%;width:100%;height:auto;min-height:0;margin:0;padding:1cqw 2cqw;animation:none!important}
#app .section-screen[hidden]{display:none}
#app .section-screen>.section-panel,#app #bookScreen>.section-panel,#app #boardScreen>.section-panel{height:100%;max-height:none;min-height:0;padding:3cqw 2.6cqw;border:.4cqw solid #9860c6;border-radius:5cqw;background:linear-gradient(#3d205bea,#24143af5);overflow:auto}
#app .section-head{min-height:19cqw;padding-right:20cqw;gap:1.5cqw 2cqw}
#app .section-head h2{font:900 5.3cqw Nunito;color:#fff0d0}
#app .section-head .tiny-label{font-size:1.7cqw}
#app .section-panel::before{width:22cqw;height:22cqw;top:1cqw;right:1cqw}
#app .back-button,#app .game-actions .square-button{border:.3cqw solid #ab72d7;background:linear-gradient(#703fa0,#47246c);box-shadow:inset 0 .4cqw .4cqw #cda0ef66,0 .5cqw 0 #29133e;color:#fff0ca}
#app .back-button{height:8cqw;padding:0 2cqw;border-radius:2.5cqw;font:800 2.6cqw Nunito}
#app .shop-grid{gap:2cqw}
#app .shop-card,#app .shop-card.bundle{padding:5cqw 1.5cqw 2cqw;border:.3cqw solid #8756b2;border-radius:3.5cqw;background:linear-gradient(145deg,#583078,#341c4f);box-shadow:inset 0 .3cqw .5cqw #b882d738,0 .7cqw 1cqw #17092555}
#app .shop-art{height:15cqw;width:100%}
#app .chest-art{width:17cqw;height:15cqw;background:url(assets/ui/illustrations/rewards.webp) center/contain no-repeat}
#app .chest-art svg{visibility:hidden}
#app .shop-heading{font:900 2.5cqw Nunito;margin:3cqw 0 2cqw;color:#dcc3f3}
#app .shop-title{font-size:3cqw}
#app .shop-amount{font-size:5cqw}
#app .shop-price{padding:1.4cqw 3cqw}
#app .shop-price b{font-size:3.6cqw}
#app .shop-tag{font-size:2cqw}
#app .shop-bonus,#app .shop-save{font-size:2.2cqw}
#app .shop-contents{min-height:13cqw}
#app .chip{font-size:2.8cqw;background:#27133f;border-color:#ac80ca33;padding:.6cqw 1.3cqw}
#app .daily-grid{gap:2cqw}
#app .daily-cell{min-height:23cqw;padding:2cqw 1cqw;gap:1cqw;background:linear-gradient(#543074,#301945);border:.3cqw solid #8053a7;border-radius:3cqw}
#app .daily-cell.grand{background:linear-gradient(120deg,#64432c,#42243e);border-color:#d2a356}
#app .daily-day{font-size:2.4cqw;color:#e2cafa}
#app .daily-art{height:10cqw}
#app .daily-art>svg{width:8cqw;height:8cqw}
#app .daily-lead{font-size:2.9cqw;line-height:1.4}
#app .daily-claim{font-size:3.5cqw;min-height:11cqw;border-radius:4cqw}
#app #bookScreen .book-card{grid-template-columns:24cqw 1fr;gap:1.5cqw 2cqw;padding:2cqw;background:linear-gradient(#4b2a68,#301a45);border:.3cqw solid #8156a6}
#app #bookScreen .book-art{width:24cqw;height:25cqw;grid-row:1/4;background:radial-gradient(#503160,#291b3b)}
#app #bookScreen .book-card h3{font-size:3.8cqw;gap:1.3cqw}
#app #bookScreen .book-card p,#app #bookScreen .book-card ul{font-size:3cqw;line-height:1.45}
#app #bookScreen .book-card ul,#app #bookScreen .book-tip{grid-column:1/-1}
#app #bookScreen .book-card .book-tip{font-size:2.7cqw;background:#28183f}
#app .book-meta{font-size:2.4cqw;grid-column:1/-1}
#app .book-icon{width:7cqw;height:7cqw;font-size:4cqw;background:#382048;border-color:#98704d}

/* Playfield height uses its actual container; no clipped bottom row. */
#app #gameScreen{position:absolute;inset:8% 0 0;height:auto;width:100%;min-height:0;padding:0 2cqw 1.5cqw;animation:none!important}
#app .game-topline{flex:0 0 16cqw;min-height:16cqw;padding:1.5cqw;border-radius:4cqw;background:linear-gradient(#4b256c,#321746)}
#app .game-actions .square-button{width:9cqw;height:9cqw;font-size:6cqw;border-radius:2.7cqw}
#app .moves-pill{padding:1.5cqw 2cqw;gap:1cqw;background:#2e153d;border-color:#785294}
#app .moves-pill b{font-size:5cqw}#app .moves-pill>span{font-size:2.4cqw}
#app .star-goal{background:none;box-shadow:none;border:0}
#app .star-goal>div{font-size:5.8cqw}#app .star-goal>span{font-size:2.3cqw}
#app .rule-badge{font-size:2.1cqw!important;color:#e6cff5;background:#3b2250;border-color:#8960a4}
#app #arena{flex:1 1 0;height:0;min-height:0!important;margin:1cqw 0;overflow:visible;background:radial-gradient(ellipse,#77349429,transparent 75%);border:.25cqw solid #8550b75e;border-radius:6cqw}
#app #sandCanvas{top:-110px}
#app .message-strip{flex:0 0 8cqw;min-height:8cqw;display:grid;place-items:center;padding:1cqw;font-size:2.5cqw;line-height:1.3;border-radius:3cqw;background:#321645}
#app .booster-dock{flex:0 0 21cqw;min-height:0;height:21cqw;margin:2cqw 0 0;padding:2.5cqw 1cqw 1cqw;border-radius:4cqw;background:linear-gradient(#492568,#301643)}
#app .booster{background:none;box-shadow:none;gap:.4cqw}
#app .booster-icon{width:10cqw;height:10cqw;border-radius:2.8cqw;background:linear-gradient(#744b97,#46246a);border-color:#b786d1}
#app .booster-icon svg{width:6cqw;height:6cqw}#app .booster-name{font-size:2.3cqw}#app .booster-price{font-size:2.3cqw!important}
#app .dock-caption{font-size:1.8cqw;background:#44205d}
dialog{width:min(50dvh,94vw);max-height:min(90dvh,160vw);font-family:Nunito,sans-serif;border:2px solid #9a68bb;background:linear-gradient(#4b296a,#25123c)}
.world{filter:saturate(.85);background-image:linear-gradient(#25133699,#36194c44 50%,#1c102acd),url(assets/workshop.webp)}
#app .wallet-plus{top:50%;translate:0 -50%;transform:none}
#app .adventure-card .logo-subtitle{text-transform:none}
.crystal-gem{background:url(assets/ui/icons/gem.webp) center/contain no-repeat;clip-path:none;filter:drop-shadow(0 1px 2px #2c075a66)}
.crystal-gem::after{display:none}
#app .gem-wallet{border-color:#673183!important;box-shadow:inset 0 .4cqw .5cqw #af6fc723,0 .4cqw .7cqw #1b052744!important}
#app .daily-grid{grid-template-columns:repeat(3,minmax(0,1fr))}
#app .daily-cell{min-height:25cqw}
#app .daily-cell.grand{grid-column:1/-1;min-height:25cqw;position:relative;overflow:hidden;background:radial-gradient(ellipse at 50% 80%,#98612966,transparent 70%),linear-gradient(120deg,#5f3c34,#3e234b);box-shadow:inset 0 0 0 .6cqw #ffd87917}
#app .daily-cell.grand .daily-art{height:12cqw}
#app .daily-cell.grand .chest-art{height:14cqw}
#app .daily-art .crystal-gem.big{width:9cqw;height:10cqw}
#app .daily-claim:disabled{opacity:.8;filter:saturate(.55);font-size:3cqw}
#app #shopGems{grid-template-columns:repeat(3,minmax(0,1fr))}
#app #shopGems .shop-card{padding:2cqw 1cqw}
#app #shopGems .shop-title{font-size:2.6cqw;min-height:7cqw;display:grid;place-items:center;line-height:1.2}
#app #shopGems .shop-amount{font-size:4cqw;gap:.5cqw}
#app #shopGems .shop-price{padding:1.5cqw 2cqw}
#app #shopGems .shop-price b{font-size:3cqw}
#app .gem-pile{width:21cqw}
#app .gem-pile .crystal-gem{width:6cqw;height:7cqw;margin:-2cqw -1cqw 0}
#app .shop-art{align-items:center}
#app #shopBundles .shop-card:last-child{grid-column:1/-1;display:grid;grid-template-columns:25cqw 1fr;padding:3cqw;gap:2cqw}
#app #shopBundles .shop-card:last-child .shop-art{grid-row:1/4;height:100%}
#app #shopBundles .shop-card:last-child .chest-art{width:24cqw;height:24cqw}
#app #shopBundles .shop-card:last-child .shop-price{justify-self:center}
#app .shop-balance{background:#2e183f;border-color:#795292;color:#dec6ef}
#app .shop-balance b,#app .shop-amount{color:#ecdcff}
#app .section-screen::before,#app .section-screen::after{bottom:-1cqw;width:14cqw;height:14cqw}
#app #mainNav .active::after{content:'';position:absolute;pointer-events:none;bottom:-2.7cqw;left:calc(50% - 2.5cqw);width:5cqw;height:5cqw;background:url(assets/ui/icons/sparkle.webp) center/contain no-repeat}
#settingsDialog{width:min(50dvh,94vw);padding:32px 20px 22px}
#settingsDialog h2{font:900 clamp(20px,3dvh,30px) Nunito;color:#fff0ce}
dialog .square-button,dialog .small-button,dialog select{background:linear-gradient(#68408a,#3b2056);border-color:#a576c4;color:#f5e8ff}
dialog .mixer-row label{font-size:clamp(12px,1.8dvh,17px)}
dialog .mixer-row{gap:10px;margin-top:20px}
dialog .mixer-row .small-button{padding:8px;font-size:12px;min-height:36px}
.boot{background:radial-gradient(ellipse at 50% 40%,#47235f,#1d102d 72%)}
.boot-card{width:min(90vw,50dvh)}
.boot-logo{font:900 clamp(22px,4dvh,38px) Nunito;color:#ffdfa1}
.boot-sub{font-size:clamp(12px,2dvh,18px);letter-spacing:1px}
.boot-bar{max-width:100%;border-color:#a76ace;background:#271239}
.boot-bar i{background:linear-gradient(90deg,#c87df5,#ffdd78)}
#app .game-level-caption{display:block;font:900 2.5cqw Nunito;line-height:1;color:#ffedc2;letter-spacing:.1cqw}
#app .star-goal>div{font-size:4.8cqw;line-height:1.1;margin:.4cqw 0}
#app .star-goal>span{font-size:2.1cqw}
#app .rule-badge{font-size:1.8cqw!important;margin-top:.5cqw}
#settingsDialog .mixer-row{background:linear-gradient(#3c2352,#2c193f);border-color:#805b9c}
#settingsDialog select,#settingsDialog .mixer-value{background:#311b43;border-color:#9d72b5;color:#eee0fc}
button:focus-visible,input:focus-visible,select:focus-visible{outline-color:#ffdf87}

/* Reward state comes from dailyStatus(), never from decorative defaults. */
#app .notify-dot[hidden]{display:none!important}
#app .score-trophy{display:block;object-fit:contain}
#app .coin-wallet{padding-right:1cqw}

#app .preview-goals{height:75%;display:flex;align-items:center;justify-content:center;gap:2cqw}
#app .preview-stars{display:flex;align-items:center;justify-content:center;gap:1cqw}
#app .preview-stars img{width:7cqw;height:7cqw;object-fit:contain;filter:drop-shadow(0 .4cqw .4cqw #ac682544)}
#app .preview-stars img:nth-child(2){width:8cqw;height:8cqw}
#app .preview-star-target{font:800 2.6cqw Nunito;color:#eedcff;white-space:nowrap}

#app .game-topline{display:grid;grid-template-columns:18cqw minmax(0,1fr) 20cqw;gap:1.5cqw;align-items:center;flex:0 0 24cqw;min-height:24cqw;padding:2.5cqw 2cqw}
#app .star-goal{position:static;left:auto;translate:none;transform:none;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.8cqw;min-width:0;width:100%;padding:0}
#app .game-level-caption{font:900 3cqw/1.2 Nunito;margin:0}
#app .star-goal>div{font-size:5.5cqw;line-height:1.05;letter-spacing:.5cqw;margin:0}
#app .star-goal>span{font:700 2.25cqw/1.3 Nunito;margin:0;white-space:normal}
#app .star-goal .rule-badge{position:static;margin:0;padding:.5cqw 1.3cqw!important;max-width:100%;font:800 1.8cqw/1.35 Nunito!important;white-space:normal;letter-spacing:.08cqw;text-wrap:balance}
#app .game-actions{justify-content:flex-end;gap:1cqw}
#app .moves-pill{justify-content:center;gap:.7cqw;padding:2cqw 1cqw}
.helper-sprite{display:block;object-fit:contain;pointer-events:none}
#app .booster-icon .helper-sprite{width:100%;height:100%;filter:drop-shadow(0 .4cqw .4cqw #1b092c66)}
#app .booster-icon{padding:.2cqw}
.chip-icon .helper-sprite{width:100%;height:100%}
#app .daily-art>.helper-sprite{width:10cqw;height:10cqw}
.helper-emblem>.helper-sprite{width:80px;height:80px;margin:auto}

/* Leaderboard: fixed heading and score card, independently scrolling rows.
   Explicit minmax tracks prevent the legacy list height from squeezing the header. */
#app #boardScreen{bottom:2%}
#app #boardScreen>.section-panel{display:grid;grid-template-rows:auto auto minmax(0,1fr);gap:2.5cqw;overflow:hidden;padding:3cqw 2.6cqw 4cqw}
#app #boardScreen .section-head{display:grid;grid-template-columns:auto minmax(0,1fr);min-height:9cqw;margin:0;padding:0;gap:2cqw}
#app #boardScreen .section-head h2{margin:0;font:900 4.7cqw/1.15 Nunito;color:#fff0d0;text-wrap:balance;overflow-wrap:anywhere}
#app #boardScreen .board-me{display:flex;align-items:center;gap:2cqw;width:100%;min-width:0;margin:0;padding:1.5cqw 2.5cqw;border:.25cqw solid #9365ba;border-radius:3cqw;background:linear-gradient(110deg,#543075,#321b4c);box-shadow:inset 0 .3cqw .5cqw #c590e526}
#app #boardScreen .board-trophy{flex:0 0 9cqw;width:9cqw;height:9cqw;object-fit:contain;filter:drop-shadow(0 .4cqw .5cqw #16072066)}
#app #boardScreen .board-points{display:flex;flex-direction:column;gap:.3cqw;min-width:0;text-align:left}
#app #boardScreen .board-points>span{font:700 2.7cqw/1.2 Nunito;color:#d9c4ed}
#app #boardScreen .board-points>b{font:900 4.5cqw/1.1 Nunito;color:#ffdf8d;overflow-wrap:anywhere}
#app #boardScreen .board-place{flex:none;margin:0 0 0 auto;padding:1.4cqw 2cqw;border:.25cqw solid #bd8dd7;border-radius:2cqw;background:#28153f;font:800 3cqw/1.2 Nunito;color:#f6e3ff}
#app #boardScreen .board-layout{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(0,1fr) auto;gap:2.5cqw;min-height:0;overflow:hidden}
#app #boardList{display:flex;flex-direction:column;gap:1.5cqw;min-height:0;height:auto;max-height:none;margin:0;padding:0 1.5cqw 0 0;overflow-x:hidden;overflow-y:auto;scrollbar-gutter:stable;scrollbar-color:#a271c1 #241337;scroll-padding-block:1cqw}
#app #boardList::-webkit-scrollbar{width:1cqw}
#app #boardList::-webkit-scrollbar-thumb{background:#a271c1}
#app #boardList>.board-row{flex:0 0 auto;display:grid;grid-template-columns:6.5cqw minmax(0,1fr) auto;gap:1.5cqw;min-height:10.5cqw;margin:0;padding:1.5cqw;border:.25cqw solid #765091;border-radius:2.8cqw;background:linear-gradient(110deg,#462562,#2e1a44)}
#app #boardList>.board-row.you{border-color:#ffdc83;background:linear-gradient(110deg,#674729,#3f2946);box-shadow:inset 0 0 2cqw #ffd76c13}
#app #boardScreen .board-rank{font:900 3.5cqw/1 Nunito;color:#ffdc8c}
#app #boardScreen .board-player{gap:1.5cqw}
#app #boardScreen .board-avatar{width:6.5cqw;height:6.5cqw;border:.25cqw solid #ab7bc4;background-color:#3c2257;color:#ead5ff;font:900 3cqw Nunito}
#app #boardScreen .board-row.you .board-avatar{border-color:#ffdc83}
#app #boardScreen .board-name{font:800 2.9cqw/1.25 Nunito;color:#f1e4fb}
#app #boardScreen .board-score{font:900 3.2cqw/1.2 Nunito;color:#ffe4a1;font-variant-numeric:tabular-nums;white-space:nowrap}
#app #boardScreen .board-gap{flex:none;padding:.5cqw 0;font-size:3.5cqw;line-height:1;color:#bb8fd2}
#app #boardScreen .board-rules{margin:0;padding:2.5cqw 3cqw;gap:1.1cqw;border:.25cqw solid #795095;border-radius:3cqw;background:linear-gradient(135deg,#402157,#2d173f);font:600 2.7cqw/1.35 Nunito!important;color:#decbec}
#app #boardScreen .board-rules b{font-size:3cqw;color:#ffdfa1}

/* Shop shelves: product-specific artwork, consistent price baseline and airy contents. */
#app #shopScreen>.section-panel{padding:3cqw 2.6cqw 5cqw;background:radial-gradient(ellipse at 85% 0,#70419744,transparent 40%),linear-gradient(#3d205bf5,#24143af7)}
#app #shopScreen .shop-heading{display:flex;align-items:center;gap:2cqw;margin:4cqw 0 2cqw;font:900 2.8cqw/1.25 Nunito;letter-spacing:.16cqw;color:#e4c8f6}
#app #shopScreen .shop-heading::after{content:'';flex:1;height:.25cqw;background:linear-gradient(90deg,#a474c377,transparent)}
#app #shopScreen .shop-grid{gap:2.2cqw;align-items:stretch}
#app #shopScreen .shop-card{--product-glow:#ac78e940;isolation:isolate;gap:1.8cqw;padding:2.5cqw 1.7cqw 2.8cqw;border:.3cqw solid #9160b4;border-radius:3.5cqw;background:radial-gradient(ellipse at 50% 20%,var(--product-glow),transparent 62%),linear-gradient(145deg,#523171,#301a46);box-shadow:inset 0 .4cqw .5cqw #dda6ff2b,inset 0 -.6cqw 1cqw #1c0b332e,0 .8cqw 1.5cqw #13081d55}
#app #shopScreen .shop-art{display:grid;place-items:center;flex:none;width:100%;height:26cqw;margin:0;overflow:visible}
#app #shopScreen .shop-product-sprite{display:block;width:100%;height:100%;object-fit:contain;pointer-events:none;filter:drop-shadow(0 1cqw 1cqw #16082566)}
#app #shopScreen .shop-title{display:grid;place-items:center;min-height:8cqw;margin:0;font:900 3.2cqw/1.2 Nunito;color:#fff0cf;text-wrap:balance}
#app #shopScreen .shop-contents{gap:1cqw;min-height:15cqw;width:100%;padding:1cqw 0;align-content:center}
#app #shopScreen .chip{gap:.5cqw;padding:.7cqw 1cqw;font:900 2.7cqw/1.2 Nunito;border-radius:1.7cqw;border-color:#b582d22b;background:#241238b8}
#app #shopScreen .chip-icon{width:4cqw;height:4cqw}
#app #shopScreen .chip .crystal-gem{width:2.8cqw;height:3.5cqw}
#app #shopScreen .shop-price{justify-content:center;align-items:center;min-height:8.5cqw;max-width:100%;margin:auto 0 0;padding:1.3cqw 3.4cqw;border:.25cqw solid #ffe9a0;border-radius:2.3cqw;background:linear-gradient(#fff0a8,#ffcf69 70%,#efaa43);box-shadow:inset 0 .45cqw .3cqw #fff8c5,0 .6cqw 0 #96602c,0 1cqw 1.5cqw #1b0c2844;color:#583012}
#app #shopScreen .shop-price b{font:900 3.5cqw/1.15 Nunito;overflow-wrap:anywhere}
#app #shopGems .shop-card{padding:2cqw 1.3cqw 2.7cqw}
#app #shopGems .shop-art{height:24cqw}
#app #shopGems .shop-title{min-height:10cqw;font-size:2.9cqw}
#app #shopGems .shop-amount{gap:.8cqw;margin:0;font:900 4.2cqw/1.2 Nunito;color:#dceeff}
#app #shopGems .shop-amount .crystal-gem{width:3cqw;height:3.8cqw}
#app #shopGems .shop-price{width:90%;padding:1.3cqw 1cqw}
#app #shopGems .shop-price b{font-size:3.2cqw}
#app #shopScreen [data-product=gems_500]{--product-glow:#4ba4cd33}
#app #shopScreen [data-product=gems_1200]{--product-glow:#c273e94d}
#app #shopScreen [data-product=gems_2000]{--product-glow:#66c7e64a;border-color:#aa82cb}
#app #shopScreen [data-product=bundle_apprentice]{--product-glow:#bd884c3d}
#app #shopScreen [data-product=bundle_alchemist]{--product-glow:#ad59f05c}
#app #shopBundles .shop-card:last-child{grid-template-columns:32cqw minmax(0,1fr);gap:1.5cqw 2cqw;padding:3cqw;background:radial-gradient(ellipse at 20% 45%,#da9b4238,transparent 65%),linear-gradient(120deg,#58324f,#352049);border-color:#d2a75f;box-shadow:inset 0 0 0 .6cqw #e9be6612,0 .8cqw 1.5cqw #13081d55}
#app #shopBundles .shop-card:last-child .shop-art{grid-column:1;grid-row:1/4;height:34cqw;align-self:center}
#app #shopBundles .shop-card:last-child .shop-title{grid-column:2;min-height:0;font-size:3.5cqw}
#app #shopBundles .shop-card:last-child .shop-contents{grid-column:2;min-height:0}
#app #shopBundles .shop-card:last-child .shop-price{grid-column:2;justify-self:center}
#app #shopScreen .shop-card.perk{display:grid;grid-template-columns:22cqw minmax(0,1fr);gap:1.7cqw 2.5cqw;padding:3cqw;text-align:left;--product-glow:#71b79330}
#app #shopScreen .shop-card.perk .shop-art{grid-column:1;grid-row:1/4;height:25cqw;align-self:center}
#app #shopScreen .shop-card.perk .shop-title{grid-column:2;min-height:0;display:block;font-size:3.7cqw}
#app #shopScreen .shop-card.perk .perk-text{grid-column:2;min-height:0;padding:0;display:block;font:600 2.9cqw/1.4 Nunito;color:#dfcee9}
#app #shopScreen .shop-card.perk .shop-price{grid-column:2;justify-self:start;margin:0}
#app #shopScreen .shop-card.owned .shop-price{background:linear-gradient(#d4e6b0,#b7cc9a);border-color:#e5f2c7;box-shadow:inset 0 .4cqw .3cqw #f5ffe0,0 .5cqw 0 #677446}
#app #shopScreen .shop-card.owned .shop-price b{color:#35472b}

/* Motion layer. Entrances run only while app.js arrive() keeps .arrive on a just-opened screen, so re-rendered
   cards never replay. Entrances use fill "backwards": once finished they release translate/scale, and the
   base press offset keeps working. Only opacity and individual translate/scale/rotate are animated, so the
   transform-based layout stays intact. Idle rules come first; entrance rules below override them while arriving. */
@keyframes mo-rise{from{opacity:0;translate:0 4cqw}to{opacity:1;translate:0 0}}
@keyframes mo-drop{from{opacity:0;translate:0 -4cqw}to{opacity:1;translate:0 0}}
@keyframes mo-left{from{opacity:0;translate:-4cqw 0}to{opacity:1;translate:0 0}}
@keyframes mo-pop{0%{opacity:0;scale:.55}65%{opacity:1;scale:1.08}100%{opacity:1;scale:1}}
@keyframes mo-zoom{from{opacity:0;scale:.92}to{opacity:1;scale:1}}
@keyframes mo-fade{from{opacity:0}to{opacity:1}}
@keyframes mo-float{0%,100%{translate:0 0}50%{translate:0 -1.3cqw}}
@keyframes mo-hover{0%,100%{translate:0 0}50%{translate:0 -6px}}
@keyframes mo-twinkle{0%,100%{opacity:.6;scale:.8;rotate:0deg}50%{opacity:1;scale:1.15;rotate:35deg}}
@keyframes mo-sway{0%,100%{rotate:0deg}50%{rotate:var(--sway,3deg)}}
@keyframes mo-breathe{0%,100%{opacity:.25;scale:.9}50%{opacity:.7;scale:1.06}}
@keyframes mo-motes{0%{opacity:0;translate:0 5cqw}25%,70%{opacity:1}100%{opacity:0;translate:0 -7cqw}}
@keyframes mo-shine{0%,55%{background-position:110% 0,0 0}100%{background-position:-10% 0,0 0}}
@keyframes mo-halo{0%,100%{box-shadow:inset 0 0 1.2cqw #fff9bf,0 0 1cqw #ffcc5855}50%{box-shadow:inset 0 0 1.2cqw #fff9bf,0 0 3.4cqw #ffcc58cc}}
@keyframes mo-spin{0%,100%{rotate:-8deg;scale:1}50%{rotate:8deg;scale:1.1}}
@keyframes mo-wiggle{0%,70%,100%{rotate:0deg}76%{rotate:-14deg}82%{rotate:12deg}88%{rotate:-8deg}94%{rotate:4deg}}
@keyframes mo-nudge{0%,60%,100%{translate:0 0}80%{translate:.8cqw 0}}
@keyframes mo-nudge-back{0%,60%,100%{translate:0 0}80%{translate:-.8cqw 0}}
@keyframes mo-bump{0%{scale:1}35%{scale:1.25}100%{scale:1}}
@keyframes mo-dialog{0%{opacity:0;scale:.86}70%{opacity:1;scale:1.02}100%{opacity:1;scale:1}}
@keyframes mo-star{0%{opacity:0;scale:.2;rotate:-140deg}60%{opacity:1;scale:1.35;rotate:12deg}100%{opacity:1;scale:1;rotate:0deg}}
@keyframes mo-star-glow{0%,100%{filter:drop-shadow(0 3px 2px #5a2a1a88) drop-shadow(0 0 6px #ffd76a55)}50%{filter:drop-shadow(0 3px 2px #5a2a1a88) drop-shadow(0 0 18px #ffd76acc)}}

/* Stagger index for repeated cards. */
#app :is(.chapter-tab,.level-cell,.map-action,.booster,.shop-card,.daily-cell,.book-card,.board-row,.board-gap):nth-child(2){--n:1}
#app :is(.chapter-tab,.level-cell,.map-action,.booster,.shop-card,.daily-cell,.book-card,.board-row,.board-gap):nth-child(3){--n:2}
#app :is(.chapter-tab,.level-cell,.map-action,.booster,.shop-card,.daily-cell,.book-card,.board-row,.board-gap):nth-child(4){--n:3}
#app :is(.chapter-tab,.level-cell,.map-action,.booster,.shop-card,.daily-cell,.book-card,.board-row,.board-gap):nth-child(5){--n:4}
#app :is(.chapter-tab,.level-cell,.map-action,.booster,.shop-card,.daily-cell,.book-card,.board-row,.board-gap):nth-child(6){--n:5}
#app :is(.chapter-tab,.level-cell,.map-action,.booster,.shop-card,.daily-cell,.book-card,.board-row,.board-gap):nth-child(7){--n:6}
#app :is(.chapter-tab,.level-cell,.map-action,.booster,.shop-card,.daily-cell,.book-card,.board-row,.board-gap):nth-child(8){--n:7}
#app :is(.chapter-tab,.level-cell,.map-action,.booster,.shop-card,.daily-cell,.book-card,.board-row,.board-gap):nth-child(9){--n:8}
#app :is(.chapter-tab,.level-cell,.map-action,.booster,.shop-card,.daily-cell,.book-card,.board-row,.board-gap):nth-child(n+10){--n:9}

/* Idle life: map decor, current level, active section, wallets and notifications. */
#app .card-sparkle{animation:mo-twinkle 3.2s ease-in-out infinite}
#app .card-sparkle-bottom{animation-delay:-1.6s}
#app .card-leaves-left{--sway:-4deg;animation:mo-sway 4.6s ease-in-out infinite}
#app .card-leaves-right{--sway:4deg;animation:mo-sway 5.2s ease-in-out -1.3s infinite}
#app .mini-scene .level-hero-art{animation:mo-float 5s ease-in-out infinite}
#app .mini-scene::before{content:'';position:absolute;z-index:1;inset:6% 22% 4%;border-radius:50%;pointer-events:none;background:radial-gradient(closest-side,#ffe3867a,#d59bff2e 60%,transparent);mix-blend-mode:screen;animation:mo-breathe 3.6s ease-in-out infinite}
#app .mini-scene::after{content:'';position:absolute;z-index:1;inset:0 12% 6%;pointer-events:none;background:radial-gradient(circle,#ffeaa8 0 .3cqw,transparent .45cqw) 1cqw 2cqw/11cqw 9cqw,radial-gradient(circle,#e6bdff 0 .25cqw,transparent .4cqw) 6cqw 5cqw/13cqw 11cqw;mask-image:radial-gradient(ellipse at center,#000 35%,transparent 72%);animation:mo-motes 5.5s linear infinite}
#app .preview-stars img{animation:mo-float 2.6s ease-in-out infinite}
#app .preview-stars img:nth-child(2){animation-delay:-.45s}
#app .preview-stars img:nth-child(3){animation-delay:-.9s}
#app #playBtn{background-image:linear-gradient(105deg,transparent 38%,#fffbe0d0 50%,transparent 62%),linear-gradient(165deg,#ffe77a,#ffd15c 60%,#ffb33c);background-size:250% 100%,100% 100%;background-repeat:no-repeat;background-position:110% 0,0 0;animation:mo-shine 3.8s ease-in-out 1s infinite}
#app .level-cell.current{animation:mo-halo 2.2s ease-in-out infinite}
#app #levelNext img{animation:mo-nudge 2.8s ease-in-out infinite}
#app #levelPrev img{animation:mo-nudge-back 2.8s ease-in-out 1.4s infinite}
#app #mainNav .map-action.active>img{animation:mo-float 2.8s ease-in-out infinite}
#app #mainNav .active::after{animation:mo-twinkle 2.4s ease-in-out infinite}
#app .gem-wallet img{animation:mo-spin 3.4s ease-in-out infinite}
#app .mail-button:has(#mailDot:not([hidden]))>img{animation:mo-wiggle 2.6s ease-in-out infinite}
#app #dailyBtn:has(#dailyDot:not([hidden]))>img,#app #bookBtn:has(#bookDot:not([hidden]))>img{animation:mo-wiggle 3s ease-in-out infinite}
#app .booster-icon .helper-sprite{animation:mo-float 3.2s ease-in-out infinite;animation-delay:calc(var(--n,0)*-.6s)}
#app #shopScreen .shop-art>*{animation:mo-float 3.4s ease-in-out infinite;animation-delay:calc(var(--n,0)*-.5s)}
#app .daily-cell.current .daily-art{animation:mo-float 2s ease-in-out infinite}
#app #boardScreen .board-trophy{animation:mo-spin 3.6s ease-in-out infinite}
#app button:not(:disabled):active,dialog button:not(:disabled):active{scale:.96}
#app #moves.bump,#app #liveStars.bump{animation:mo-bump .36s ease-out}
#toast{scale:.9;transition:opacity .25s ease,translate .35s cubic-bezier(.3,1.6,.5,1),scale .35s cubic-bezier(.3,1.6,.5,1)}
#toast.visible{scale:1}
.boot-logo{animation:mo-hover 2.6s ease-in-out infinite}

/* Dialogs: springy panel, floating emblem, win stars popping one by one. */
dialog[open]{animation:mo-dialog .36s cubic-bezier(.2,.9,.3,1.15) backwards}
dialog .helper-emblem{animation:mo-hover 2.8s ease-in-out infinite}
/* Win stars use the same star.png as the map goal: middle one larger and raised, unearned ones desaturated. */
#winDialog .win-stars{display:flex;justify-content:center;align-items:flex-end;gap:8px;margin:16px 0 18px;letter-spacing:0;text-shadow:none}
#winDialog .win-star{display:block;width:64px;height:64px;object-fit:contain;filter:drop-shadow(0 3px 2px #5a2a1a88);animation:mo-star .6s cubic-bezier(.3,1.5,.5,1) backwards;animation-delay:calc(.25s + var(--i)*.22s)}
#winDialog .win-star:nth-child(2){width:80px;height:80px;margin-bottom:10px}
#winDialog .win-star.dim-star{filter:grayscale(1) brightness(.45) drop-shadow(0 3px 2px #0006)}
#winDialog .win-star:not(.dim-star){animation:mo-star .6s cubic-bezier(.3,1.5,.5,1) calc(.25s + var(--i)*.22s) backwards,mo-star-glow 2.2s ease-in-out 1.2s infinite}
#winDialog[open] .win-reward{animation:mo-pop .45s cubic-bezier(.3,1.4,.5,1) .85s backwards}
#winDialog[open] .win-reward .crystal-gem{animation:mo-spin 2.6s ease-in-out 1.3s infinite}
#winDialog[open] .win-points{animation:mo-pop .45s cubic-bezier(.3,1.4,.5,1) 1s backwards}

/* Map entrance. */
#mapScreen.arrive .chapter-tab{animation:mo-drop .45s cubic-bezier(.2,.8,.3,1) backwards;animation-delay:calc(var(--n,0)*60ms)}
#mapScreen.arrive .chapter-pagination{animation:mo-fade .4s .25s backwards}
#mapScreen.arrive .adventure-card{animation:mo-zoom .5s cubic-bezier(.2,.8,.3,1) .08s backwards}
#mapScreen.arrive .level-title-frame{animation:mo-pop .5s cubic-bezier(.3,1.4,.5,1) .3s backwards}
#mapScreen.arrive .preview-stars img{animation:mo-pop .4s cubic-bezier(.3,1.5,.5,1) backwards}
#mapScreen.arrive .preview-stars img:nth-child(1){animation-delay:.5s}
#mapScreen.arrive .preview-stars img:nth-child(2){animation-delay:.6s}
#mapScreen.arrive .preview-stars img:nth-child(3){animation-delay:.7s}
#mapScreen.arrive #playBtn{animation:mo-pop .5s cubic-bezier(.3,1.4,.5,1) .45s backwards,mo-shine 3.8s ease-in-out 1s infinite}
:is(#mapScreen,#levelGrid).arrive .level-cell{animation:mo-pop .42s cubic-bezier(.3,1.4,.5,1) backwards;animation-delay:calc(.2s + var(--n,0)*45ms)}
body:not(:has(#boot:not(.done))) #app #mainNav:not([hidden]) .map-action{animation:mo-rise .42s cubic-bezier(.2,.8,.3,1) backwards;animation-delay:calc(var(--n,0)*55ms)}

/* Game entrance; the arena only fades so canvas measurements stay exact. */
#gameScreen.arrive .game-topline{animation:mo-drop .42s cubic-bezier(.2,.8,.3,1) backwards}
#gameScreen.arrive #arena{animation:mo-fade .5s .1s backwards}
#gameScreen.arrive .message-strip{animation:mo-zoom .4s .18s backwards}
#gameScreen.arrive .booster-dock{animation:mo-rise .45s cubic-bezier(.2,.8,.3,1) .12s backwards}
#gameScreen.arrive .booster{animation:mo-pop .4s cubic-bezier(.3,1.4,.5,1) backwards;animation-delay:calc(.25s + var(--n,0)*60ms)}

/* Section entrance. Leaderboard rows only fade: centerOnMe() measures them while they appear. */
.section-screen.arrive>.section-panel{animation:mo-zoom .34s cubic-bezier(.2,.8,.3,1) backwards}
.section-screen.arrive .back-button{animation:mo-left .4s cubic-bezier(.2,.8,.3,1) .1s backwards}
.section-screen.arrive .section-head>div,.section-screen.arrive .board-me,.section-screen.arrive .daily-lead{animation:mo-fade .4s .12s backwards}
.section-screen.arrive :is(.shop-card,.daily-cell,.book-card){animation:mo-rise .45s cubic-bezier(.2,.8,.3,1) backwards;animation-delay:calc(.12s + var(--n,0)*50ms)}
.section-screen.arrive .shop-heading{animation:mo-left .4s .1s backwards}
.section-screen.arrive .daily-claim{animation:mo-pop .45s cubic-bezier(.3,1.4,.5,1) .5s backwards}
.section-screen.arrive :is(.board-row,.board-gap){animation:mo-fade .4s backwards;animation-delay:calc(.1s + var(--n,0)*35ms)}
.section-screen.arrive .board-rules{animation:mo-fade .4s .3s backwards}

@media(prefers-reduced-motion:reduce){#app *,#app *::before,#app *::after,dialog,dialog *,.boot *{animation:none!important}#toast{scale:1;transition:opacity .2s}}

/* Shop products use sprites from assets/ui/shop (scripts/prepare-shop-sprites.py); tags sit on the generated ribbon. */
#app #shopScreen .shop-card{position:relative;overflow:visible}
#app #shopScreen .shop-grid{row-gap:7cqw;padding-top:3cqw}
#app #shopScreen .shop-grid.perks-grid{padding-top:0}
/* An auto grid row would let the sprite's 100% height resolve against itself and spill over the title. */
#app #shopScreen .shop-art{grid-template:minmax(0,1fr)/minmax(0,1fr)}
#app #shopScreen :is(#shopGems,#shopBundles)>.shop-card{padding-top:5.5cqw}
#app #shopBundles .shop-card:last-child .shop-tag{left:19cqw}
/* Tag text follows the ribbon arc: SVG textPath in ribbon.png pixel space (379×234), path measured from the band edges. */
#app #shopScreen .shop-tag svg{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
#app #shopScreen .shop-tag text{font:900 34px Nunito,sans-serif;letter-spacing:.5px;fill:#fff3cf;stroke:#4a1670;stroke-width:7px;stroke-linejoin:round;paint-order:stroke}
#app #shopScreen .shop-tag{position:absolute;z-index:2;top:-5.6cqw;left:50%;translate:-50% 0;display:grid;place-items:center;width:23cqw;height:14.2cqw;padding:0;border:0;border-radius:0;background:url(assets/ui/shop/ribbon.webp) center/100% 100% no-repeat;box-shadow:none;font:900 2.3cqw/1 Nunito,sans-serif;letter-spacing:0;text-transform:none;color:#fff3cf;text-shadow:0 .25cqw 0 #4a1670,0 0 1cqw #2a0b44;white-space:nowrap;pointer-events:none;filter:drop-shadow(0 .5cqw .6cqw #14062280)}
#app #shopScreen .shop-product-sprite{filter:drop-shadow(0 1cqw 1cqw #16082566) drop-shadow(0 0 2.5cqw var(--product-glow))}

/* Rating points are always marked with the trophy, including the win dialog. */
#winDialog .win-trophy{width:36px;height:36px;object-fit:contain;filter:drop-shadow(0 2px 3px #0008)}
#winDialog[open] .win-trophy{animation:mo-spin 2.8s ease-in-out 1.5s infinite}

/* Board zoom for tall levels (placeZoom/setZoom in app.js, renderer.zoom in fitArena). The bar is placed over
   #arena from JS because the arena itself scrolls while zoomed. A custom slider: the legacy range styles are horizontal. */
#app #arena.scrolling{overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:none}
#app #arena.scrolling::-webkit-scrollbar{display:none}
#app .zoom-bar{position:absolute;z-index:6;right:2.4cqw;width:8cqw;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2.4cqw;pointer-events:none}
#app .zoom-bar[hidden]{display:none}
#app .zoom-bar>*{pointer-events:auto}
#app .zoom-step{width:7.5cqw;height:7.5cqw;min-height:0;padding:0;display:grid;place-items:center;border:.3cqw solid #ab72d7;border-radius:2.4cqw;background:linear-gradient(#703fa0,#47246c);box-shadow:inset 0 .4cqw .4cqw #cda0ef66,0 .5cqw 0 #29133e;color:#ffe9a8;font:900 5cqw/1 Nunito,sans-serif}
#app .zoom-track{--zoom:0;position:relative;flex:none;width:3.2cqw;height:min(48cqw,55%);border:.3cqw solid #8e5cb8;border-radius:9cqw;background:#24123a;box-shadow:inset 0 .4cqw .8cqw #0009;touch-action:none;cursor:pointer}
#app .zoom-fill{position:absolute;left:0;right:0;bottom:0;height:calc(var(--zoom)*100%);border-radius:inherit;background:linear-gradient(#ffe38a,#e9a33e)}
#app .zoom-thumb{position:absolute;left:50%;bottom:calc(var(--zoom)*100%);width:6.5cqw;height:6.5cqw;translate:-50% 50%;border-radius:50%;border:.4cqw solid #fff3cc;background:radial-gradient(circle at 35% 30%,#fff7da,#f0c166 60%,#b07a35);box-shadow:0 .6cqw 1.2cqw #000a;pointer-events:none}
#app .zoom-track:focus-visible{outline:.5cqw solid #ffdf87;outline-offset:1cqw}

/* Status strip: fixed height so a changing message never re-lays the board; fitStatus() in app.js shrinks long texts. */
#app .message-strip{flex:0 0 12cqw;min-height:12cqw;height:12cqw;overflow:hidden;text-wrap:balance}
#app .message-strip.long,#app .message-strip.long #status{font-size:2.1cqw;line-height:1.2}

/* Tutorial bubble: wraps and stays inside the arena; the arrow keeps pointing at the tube (--arrow from renderGuide). */
#app .coach-tip{max-width:78cqw;white-space:normal;text-wrap:balance;font:800 2.9cqw/1.3 Nunito,sans-serif;padding:1.6cqw 2.6cqw;border-radius:3cqw}
#app .coach-tip:after{left:calc(50% + var(--arrow,0px))}

/* Touch devices: drop the decorations that repaint every frame (sweeping gloss, box-shadow halo, blended glow, masked motes). */
@media (pointer: coarse){
#app #playBtn{animation:none;background:linear-gradient(165deg,#ffe77a,#ffd15c 60%,#ffb33c)}
/* The entrance rule also carries mo-shine; on touch keep only the pop so the flat background never shifts. */
#mapScreen.arrive #playBtn{animation:mo-pop .5s cubic-bezier(.3,1.4,.5,1) .45s backwards}
#app .level-cell.current{animation:none}
#app .mini-scene::before,#app .mini-scene::after{display:none}
#app .card-sparkle,#app #mainNav .active::after{animation:none}
}

/* Dialogs scale with their own width instead of fixed pixels: on a phone the win and rule cards used to
   overflow and needed scrolling. The dialog is the container, so every size below is a share of its width. */
dialog{container-type:inline-size;max-height:88dvh;padding:6cqw 5cqw 5cqw}
dialog h2{font-size:7.2cqw;margin:2.5cqw 0 3cqw}
dialog p,dialog li{font-size:4cqw;line-height:1.5}
dialog .tiny-label{font-size:2.9cqw;letter-spacing:.5cqw}
dialog .dialog-note{font-size:3cqw!important;margin:4cqw 0 0}
dialog .gold-button{margin-top:3.5cqw;padding:3.6cqw 4cqw;border-radius:4cqw;font-size:5cqw;border-bottom-width:1.4cqw}
dialog .ad-button{margin-top:3cqw;padding:3.4cqw 4cqw;border-radius:4cqw;font-size:4.2cqw}
dialog .text-button{margin:3.5cqw auto 0;padding:1.2cqw;font-size:4cqw}
dialog>.close.square-button{right:3.5cqw;top:3.5cqw;width:9cqw;height:9cqw;min-height:0;font-size:5.5cqw;border-radius:2.8cqw}
dialog .helper-emblem{font-size:12cqw;margin:0 auto}
dialog .helper-emblem svg{width:14cqw;height:14cqw}
dialog .helper-emblem>.helper-sprite{width:18cqw;height:18cqw}
dialog .coach-steps{margin:4cqw 0 1cqw;padding-left:6cqw;font-size:4.1cqw;line-height:1.45}
dialog .coach-steps li{margin:2.2cqw 0}
#winDialog .win-stars{margin:4cqw 0 3cqw;gap:2cqw}
#winDialog .win-star{width:16cqw;height:16cqw}
#winDialog .win-star:nth-child(2){width:19.5cqw;height:19.5cqw;margin-bottom:2.5cqw}
#winDialog .win-reward{gap:3cqw;padding:3.5cqw;border-radius:3.5cqw}
#winDialog .win-reward b{font-size:7cqw}
#winDialog .win-reward>span:last-child{font-size:3.4cqw}
#winDialog .win-reward .crystal-gem.big{width:7cqw;height:8.5cqw}
#winDialog .win-points{margin-top:3cqw;padding:2.8cqw 3.5cqw;border-radius:3.5cqw;gap:1cqw 2.5cqw}
#winDialog .win-points span{font-size:3.4cqw}
#winDialog .win-points b{font-size:6.5cqw}
#winDialog .win-points small{font-size:3cqw}
#winDialog .win-trophy{width:9cqw;height:9cqw}
#adDialog .ad-screen{height:28cqw;font-size:4cqw}
#settingsDialog h2{font-size:7cqw}

/* Floating motes behind the flasks (moved off the canvas 2026-09-24): each <i> is as tall as the canvas area and rises by its own
   height, the dot is its ::before. Only translate and opacity animate, so the compositor runs them without main-thread work. */
#arena .motes{position:absolute;left:0;right:0;top:-110px;height:calc(100% + 110px);overflow:hidden;pointer-events:none}
#arena .motes i{position:absolute;top:0;left:var(--x);width:3px;height:100%;animation:mote-rise 90s linear var(--rise) infinite}
#arena .motes i::before{content:'';position:absolute;top:0;left:0;width:2.4px;height:2.4px;border-radius:50%;background:var(--c);animation:mote-sway 14.28s ease-in-out var(--sway) infinite alternate,mote-blink 6.28s linear var(--blink) infinite}
@keyframes mote-rise{from{translate:0 100%}to{translate:0 0}}
@keyframes mote-sway{from{translate:-18px 0}to{translate:18px 0}}
@keyframes mote-blink{0%,50%,100%{opacity:.15}25%{opacity:.25}75%{opacity:.05}}
@media(prefers-reduced-motion:reduce){#arena .motes{display:none}}
