/* Atmosphere v1 — light, depth and motion layered over the unchanged scene art.
 * Scene layers are decorative children of #frame (see js/atmosphere.js); every coordinate
 * is a percentage of the 16:9 frame, so desktop cover and the compact camera share them. */

/* ---------- 1. Scene light layers ---------- */
body{--beam:178,204,255;--beam-k:.28;--patch-k:0;--sky-k:1}
body.lights-off{--beam-k:.95;--patch-k:.9}
body[data-daylight="day"]{--beam:255,238,202;--beam-k:.6}
body[data-daylight="day"].lights-off{--beam-k:.95;--patch-k:.85}
body.clouds-on{--sky-k:.35}

.atmo{display:none;position:absolute;pointer-events:none;z-index:9;transition:opacity 1.2s ease}
body.atmo-on .atmo{display:block}
#loading{z-index:12}

/* Desk lamp: shade halo, pool on the desk top, wash on the wall, wide ambient spill. */
/* State opacity lives on the layer; breathing and flicker animate the inner element. */
.atmo-lamp{left:0;top:0;width:62%;height:92%;mix-blend-mode:screen;transition:opacity .5s ease,filter .25s ease}
.atmo-lamp i{position:absolute;inset:0;
  background:
    radial-gradient(ellipse 14.5% 14% at 36.5% 48.5%,rgba(255,228,176,.5),rgba(255,198,120,.2) 55%,rgba(255,190,110,0) 100%),
    radial-gradient(ellipse 37% 8.5% at 39.5% 74%,rgba(255,188,108,.32),rgba(255,188,108,0) 100%),
    radial-gradient(ellipse 24% 28% at 36.5% 29%,rgba(255,198,126,.13),rgba(255,198,126,0) 100%),
    radial-gradient(ellipse 63% 50% at 36.5% 50%,rgba(255,164,88,.15),rgba(255,164,88,0) 100%);
  animation:atmo-breathe 7.3s ease-in-out infinite}
.atmo-lamp i::after{content:"";position:absolute;inset:0;
  background:radial-gradient(ellipse 21% 20% at 36.5% 48.5%,rgba(255,214,150,.2),rgba(255,214,150,0) 100%);
  animation:atmo-flicker 4.3s linear infinite}
body[data-daylight="day"] .atmo-lamp{opacity:.4}
body.lights-off .atmo-lamp{opacity:0;transition-duration:.35s}
body.atmo-ignite .atmo-lamp i{animation:atmo-ignite .95s ease-out}
.lamphit:hover~.atmo-lamp{filter:brightness(1.16)}

/* The lamp shade is painted lit; tone it down when the lamp is off. */
.atmo-shade{left:13%;top:28%;width:20%;height:30%;opacity:0;mix-blend-mode:multiply;
  background:radial-gradient(ellipse 44% 38% at 48% 52%,rgba(40,36,62,.66),rgba(40,36,62,.3) 62%,rgba(40,36,62,0) 100%)}
body.lights-off .atmo-shade{opacity:1}

/* Cool night air once the warm lamp is gone. */
.atmo-cool{inset:0;opacity:0;mix-blend-mode:soft-light;
  background:linear-gradient(180deg,rgba(84,122,224,.6),rgba(34,54,132,.5))}
body.lights-off .atmo-cool{opacity:.62}
body[data-daylight="day"].lights-off .atmo-cool{opacity:.24}

/* The pane-edge glow belongs to the wall behind the chair, not on top of the furniture. */
body.atmo-on #windowGlow{z-index:4!important}

/* Candle lantern on the right shelf keeps a small flame of its own. */
.atmo-lantern{left:83%;top:1%;width:14%;height:20%;opacity:.75;mix-blend-mode:screen;
  background:radial-gradient(ellipse 24% 27% at 50% 47%,rgba(255,180,90,.6),rgba(255,150,62,.18) 55%,rgba(255,150,62,0) 100%);
  animation:atmo-candle 3.1s linear infinite}
body.lights-off .atmo-lantern{opacity:1}
body[data-daylight="day"]:not(.lights-off) .atmo-lantern{opacity:.35}

/* Window light: a soft shaft from the glass toward the desk (moon at night, sun by day). */
.atmo-beam{left:32%;top:3%;width:46%;height:72%;mix-blend-mode:screen;opacity:calc(var(--beam-k)*var(--sky-k))}
.atmo-beam i{position:absolute;inset:0;filter:blur(14px);animation:atmo-shimmer 13s ease-in-out infinite}
.atmo-beam i::before{content:"";position:absolute;inset:0;
  clip-path:polygon(17.8% 5%,62.4% 5%,91.3% 94.4%,30.4% 94.4%);
  background:linear-gradient(180deg,rgba(var(--beam),.42),rgba(var(--beam),.2) 55%,rgba(var(--beam),.05))}
/* …and the two pane-shaped patches it leaves on the empty desk once the lamp is off. */
.atmo-patch{left:40.5%;top:64.9%;width:23.5%;height:5.6%;mix-blend-mode:screen;opacity:calc(var(--patch-k)*var(--sky-k))}
.atmo-patch i{position:absolute;inset:0;filter:blur(4px)}
.atmo-patch i::before,.atmo-patch i::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(var(--beam),.3),rgba(var(--beam),.2))}
.atmo-patch i::before{clip-path:polygon(7% 10%,44% 10%,49% 92%,10% 92%)}
.atmo-patch i::after{clip-path:polygon(53% 10%,90% 10%,97% 92%,58% 92%)}

/* Floating dust and completion sparkles are drawn on one low-resolution canvas. */
#atmoDust{inset:0;width:100%;height:100%}

/* Warm bloom when a focus session completes. */
.atmo-bloom{inset:0;opacity:0;mix-blend-mode:screen;
  background:radial-gradient(ellipse 46% 52% at 50% 54%,rgba(255,216,154,.42),rgba(255,216,154,0) 100%)}
body.atmo-celebrate .atmo-bloom{animation:atmo-bloom 2.8s ease-out}

/* Focus pulls the eye inward. */
.vig{transition:box-shadow 2.4s ease,opacity 1.4s ease}
body.atmo-focus .vig{box-shadow:inset 0 0 250px 70px rgba(0,0,0,.6)}
body.atmo-focus.sa-compact .vig{box-shadow:inset 0 0 120px 30px #0009}

body.atmo-still .atmo,body.atmo-still .atmo i,body.atmo-still .atmo i::after{animation:none!important}
/* Phones mostly frame the window, not the lamp: keep the light, skip the always-on shimmer to save battery. */
@media (pointer:coarse){.atmo-lamp i,.atmo-lamp i::after,.atmo-beam i,.atmo-lantern{animation:none}}

@keyframes atmo-breathe{0%,100%{opacity:1}38%{opacity:.955}71%{opacity:.985}}
@keyframes atmo-flicker{0%,100%{opacity:.55}9%{opacity:.8}17%{opacity:.6}31%{opacity:.95}44%{opacity:.5}52%{opacity:.72}68%{opacity:.4}79%{opacity:.86}90%{opacity:.62}}
@keyframes atmo-candle{0%,100%{transform:scale(1)}14%{transform:scale(.93)}27%{transform:scale(1.05)}41%{transform:scale(.9)}58%{transform:scale(1.02)}73%{transform:scale(.95)}88%{transform:scale(1.07)}}
@keyframes atmo-ignite{0%{opacity:0}18%{opacity:.75}30%{opacity:.4}55%{opacity:1.2;filter:brightness(1.3)}100%{opacity:1;filter:brightness(1)}}
@keyframes atmo-shimmer{0%,100%{opacity:.84}45%{opacity:1}72%{opacity:.9}}
@keyframes atmo-bloom{0%{opacity:0}16%{opacity:1}100%{opacity:0}}

/* ---------- 2. Camera: slight overscan so the gentle parallax never shows an edge ---------- */
body.atmo-on:not(.sa-compact) .frame{height:103vh;width:183.12vh}
@media (min-aspect-ratio:16/9){body.atmo-on:not(.sa-compact) .frame{width:103vw;height:57.94vw}}
/* 镜头位置只给 .frame 自己用：注册成不继承，每帧改它不用把房间里所有元素的样式都重算一遍（js/atmosphere.js applyCamera） */
@property --cam-x{syntax:'<length>';inherits:false;initial-value:0px}
@property --cam-y{syntax:'<length>';inherits:false;initial-value:0px}
body.atmo-on .frame{translate:var(--cam-x,0px) var(--cam-y,0px)}
/* What is outside the window is far away: it follows the camera less than the room does. */
body.atmo-on #forest,body.atmo-on #clouds{translate:var(--far-x,0px) var(--far-y,0px);scale:1.05}
body.atmo-on #sky{translate:var(--far-x,0px) var(--far-y,0px)}

/* ---------- 3. Interface polish (desktop floating panels) ---------- */
body:not(.sa-compact) .pomo,body:not(.sa-compact) .player{
  background:linear-gradient(162deg,rgba(44,33,23,.62),rgba(16,12,9,.54));
  border:1px solid rgba(255,216,164,.2);
  box-shadow:0 18px 52px rgba(0,0,0,.5),inset 0 1px 0 rgba(255,238,210,.1);
  -webkit-backdrop-filter:blur(14px) saturate(1.2);backdrop-filter:blur(14px) saturate(1.2)}
body:not(.sa-compact) .panel-grip{display:grid;place-items:center;font-size:0;height:14px;margin:-3px 0 6px;opacity:1}
body:not(.sa-compact) .panel-grip::before{content:"";width:34px;height:4px;border-radius:99px;background:#ecd6b2;opacity:.32;transition:opacity .2s,width .2s}
body:not(.sa-compact) .panel-grip:hover::before{opacity:.72;width:46px}

.pomo .time{background:linear-gradient(180deg,#fff7e8 20%,#efcd97);-webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;color:transparent;text-shadow:none;filter:drop-shadow(0 2px 9px rgba(0,0,0,.5))}
body.atmo-running .pomo .time{animation:atmo-time 3.4s ease-in-out infinite}
.pomo .progress{overflow:visible}
.pomo .progress i{background:linear-gradient(90deg,#b46f2b,#f3c67f);box-shadow:0 0 9px rgba(243,198,127,.6);transition:width .25s linear}
.pomo .modes button.on,.pomo .start,.player .ctrls .play,.sa-compact #saMiniPlayer #saMiniPlay{
  background:linear-gradient(180deg,#ecb665,#cb8735);box-shadow:0 5px 16px rgba(214,150,70,.3),inset 0 1px 0 rgba(255,255,255,.34)}
.pomo .start{position:relative;overflow:hidden}
.pomo .start::after{content:"";position:absolute;top:0;bottom:0;left:-60%;width:45%;transform:skewX(-20deg);
  background:linear-gradient(90deg,rgba(255,255,255,0),rgba(255,255,255,.42),rgba(255,255,255,0));opacity:0}
body:not(.atmo-running) .pomo .start::after{animation:atmo-sheen 6s ease-in-out 2s infinite}
.pomo .acts button,.player .ctrls button,.pomo .modes button{transition:transform .14s ease,background .2s,box-shadow .2s,filter .2s}
@media (hover:hover){
  .pomo .acts button:hover,.player .ctrls button:hover{transform:translateY(-1px);filter:brightness(1.08)}
  body:not(.sa-compact)>.ctrl>button{transition:background .2s,transform .16s ease,box-shadow .2s}
  body:not(.sa-compact)>.ctrl>button:hover{transform:translateY(-1px);box-shadow:0 7px 18px rgba(0,0,0,.42)}
  body:not(.sa-compact)>.ctrl>button:active{transform:scale(.94)}
}
.pomo .acts button:active,.player .ctrls button:active{transform:scale(.94)}

/* A small equaliser beside the track title while music plays. */
body.atmo-playing .player .title::before,body.atmo-playing #saMiniTitle::before{content:"";display:inline-block;width:14px;height:11px;margin-right:8px;vertical-align:-1px;
  background:linear-gradient(#edb966,#edb966) 0 100%/3px 45% no-repeat,linear-gradient(#edb966,#edb966) 5.5px 100%/3px 90% no-repeat,linear-gradient(#edb966,#edb966) 11px 100%/3px 60% no-repeat;
  animation:atmo-eq .86s ease-in-out infinite alternate}

.loading{letter-spacing:.18em;animation:atmo-loading 1.8s ease-in-out infinite}

/* ---------- 4. Compact / phone bars ---------- */
.sa-compact .ctrl{background:linear-gradient(180deg,#2b2018,#1f1711);border-bottom:1px solid #d8b27a26}
.sa-compact #pomo{background:linear-gradient(180deg,#2c2118,#221911);border-color:#d8b27a33}
.sa-compact #saMiniPlayer{background:linear-gradient(180deg,#271d15,#1d150f)}
.sa-compact #saMiniPlayer button,.sa-compact .ctrl>button{transition:transform .12s ease,background .2s}
.sa-compact #saMiniPlayer button:active,.sa-compact .ctrl>button:active{transform:scale(.95)}
/* Let the room melt into the bars above and below instead of ending on a hard line. */
.sa-compact #saStage::after{content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  background:linear-gradient(180deg,rgba(23,17,12,.6),rgba(23,17,12,0) 8%,rgba(23,17,12,0) 89%,rgba(23,17,12,.66))}

/* ---------- 5. Entrance ---------- */
@media (prefers-reduced-motion:no-preference){
  body.atmo-on:not(.atmo-ready) .ctrl,body.atmo-on:not(.atmo-ready) .pomo,body.atmo-on:not(.atmo-ready) .player,body.atmo-on:not(.atmo-ready) #saMiniPlayer{opacity:0}
  body.atmo-enter .ctrl{animation:atmo-rise .7s cubic-bezier(.2,.7,.2,1) .05s backwards}
  body.atmo-enter .pomo{animation:atmo-rise .8s cubic-bezier(.2,.7,.2,1) .22s backwards}
  body.atmo-enter .player,body.atmo-enter #saMiniPlayer{animation:atmo-rise .8s cubic-bezier(.2,.7,.2,1) .38s backwards}
}
@keyframes atmo-rise{from{opacity:0;translate:0 12px}to{opacity:1;translate:0 0}}
@keyframes atmo-time{0%,100%{filter:drop-shadow(0 2px 9px rgba(0,0,0,.5))}50%{filter:drop-shadow(0 0 13px rgba(255,196,118,.5))}}
@keyframes atmo-sheen{0%,72%{left:-60%;opacity:0}76%{opacity:1}100%{left:130%;opacity:0}}
@keyframes atmo-eq{0%{background-size:3px 45%,3px 90%,3px 60%}50%{background-size:3px 95%,3px 40%,3px 85%}100%{background-size:3px 60%,3px 75%,3px 30%}}
@keyframes atmo-loading{0%,100%{color:#8a7c66}50%{color:#d2b98f}}

.atmo-setting{display:flex;align-items:center;gap:8px;margin-top:14px}
.atmo-setting input{width:18px;height:18px;accent-color:#d69646}
